# RuleBuilder

> An IFTTT style rule editor with an event trigger, nested all-of and any-of condition groups, and an ordered list of actions, read back as a plain-language sentence with the missing pieces listed.

Source: https://docs.nasaqui.com/components/rule-builder

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/rule-builder.json
```

For automations that fit "when this happens, if these are true, do that". Choose the event, build conditions as
groups that match all or any of their members (groups nest), and stack the actions. A sentence at the top reads the
rule back ("When an order is placed, if Amount is greater than 100 and Country is Saudi Arabia, then send an email"), in
English or Arabic, so the rule can be checked at a glance. What is still missing is listed. The builder edits a
`RuleDefinition` you store; `evaluateConditions` runs the condition tree against a record if you want to evaluate it.

## When to use

- Notification rules, routing, automations, filters: anything with one trigger and a yes/no test.
- Non-technical people configuring behaviour.

## When not to use

- Branching flows, loops and merges: use `workflow-canvas` or `step-editor`.
- A saved search over a table: use `filter-builder`.

## Import

```tsx
import { RuleBuilder } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"
```

## Quick start

```tsx
import { RuleBuilder, type RuleDefinition } from "@fadymondy/nasaq/web";
import { useState } from "react";

const events = [{ id: "order.created", label: "an order is placed" }];
const fields = [{ id: "amount", label: "Amount", kind: "number" as const }];
const actionTypes = [{ id: "email", label: "Send an email", fields: [{ name: "to", label: "To", kind: "text" as const, required: true }] }];

export function Rule() {
  const [rule, setRule] = useState<RuleDefinition | undefined>();
  return <RuleBuilder events={events} fields={fields} actionTypes={actionTypes} value={rule} onValueChange={(next) => setRule(next)} />;
}
```

## Anatomy

```
RuleBuilder               data-slot="rule-builder"
├─ summary sentence       data-slot="rule-summary", aria-live polite
├─ Alert                  what is still missing
├─ 1 When                 event Select
├─ 2 If                   group (role="group"): Match all / any, condition rows, nested groups
│  └─ condition row       field, operator, value
└─ 3 Then                 Repeater of actions with fields from the action type
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `events` | `RuleEvent[]` | required | `{ id, label, description? }`. |
| `fields` | `RuleField[]` | required | `{ id, label, kind: "text" \| "number" \| "select" \| "boolean", options? }`. |
| `actionTypes` | `RuleActionType[]` | required | `{ id, label, description?, fields?, defaults? }`; fields use the workflow field definitions. |
| `value / defaultValue` | `RuleDefinition` | empty rule | `{ event, conditions: RuleGroup, actions: RuleAction[] }`. |
| `onValueChange` | `(rule, issues) => void` | none | Every change, with what is still wrong. |
| `maxDepth` | `number` | `3` | How deep condition groups may nest. |
| `disabled` | `boolean` | `false` | Read only. |
| `header` | `ReactNode` | none | Extra content under the sentence, such as a name field or Save button. |
| `labels` | `RuleBuilderLabels` | none | Override any English or Arabic string, including operator names. |

### Helpers

`emptyRule`, `validateRule`, `evaluateConditions(group, data, fields)`, `describeRule` are exported and pure.

## Examples

Save only when nothing is missing:

```tsx
<RuleBuilder events={events} fields={fields} actionTypes={actionTypes} onValueChange={(rule, issues) => setCanSave(issues.length === 0)} />
```

## Accessibility

| Key | Action |
| --- | --- |
| Tab | Moves through the event, each condition's field, operator, value and remove button, then add buttons. |
| Arrow keys | Move between "All of these" and "Any of these". |
| Enter / Space | Open a select, press a button. |

Every group has `role="group"` with its match mode as the name. The sentence is a polite live region. Problems are listed as text. Remove buttons carry names.

## RTL & i18n

- The whole builder mirrors; the sentence uses `dir="auto"`.
- Operators, "all of these", "if" and "then" ship in English and Arabic; event, field and action names come from your data.
- Numbers stay left-to-right.

## Styling & tokens

- Nested groups get `--nq-surface-soft`. Extend with `className`; never pass raw hex.

## Do / Don't

- Do name events, fields and actions in the user's words.
- Do validate again where the rule runs.
- Don't nest deeper than three levels; nobody can read it.

## Related

- [`workflow-canvas`](https://docs.nasaqui.com/components/workflow-canvas)
- [`step-editor`](https://docs.nasaqui.com/components/step-editor)
- [`cron-builder`](https://docs.nasaqui.com/components/cron-builder)

## Lab

https://docs.nasaqui.com/?path=/docs/components-workflow-rule-builder--docs

## Code

### React

```tsx
import { RuleBuilder, type RuleDefinition } from "@fadymondy/nasaq/web";
import { useState } from "react";

const events = [{ id: "order.created", label: "an order is placed" }];
const fields = [{ id: "amount", label: "Amount", kind: "number" as const }];
const actionTypes = [{ id: "email", label: "Send an email", fields: [{ name: "to", label: "To", kind: "text" as const, required: true }] }];

export function Rule() {
  const [rule, setRule] = useState<RuleDefinition | undefined>();
  return <RuleBuilder events={events} fields={fields} actionTypes={actionTypes} value={rule} onValueChange={(next) => setRule(next)} />;
}
```

### shadcn

```tsx
import { RuleBuilder, type RuleDefinition } from "@/components/ui/rule-builder";
import { useState } from "react";

const events = [{ id: "order.created", label: "an order is placed" }];
const fields = [{ id: "amount", label: "Amount", kind: "number" as const }];
const actionTypes = [{ id: "email", label: "Send an email", fields: [{ name: "to", label: "To", kind: "text" as const, required: true }] }];

export function Rule() {
  const [rule, setRule] = useState<RuleDefinition | undefined>();
  return <RuleBuilder events={events} fields={fields} actionTypes={actionTypes} value={rule} onValueChange={(next) => setRule(next)} />;
}
```

### Vue

```vue
<script setup lang="ts">
import { NqRuleBuilder, type RuleDefinition } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const events = [{ id: "order.created", label: "an order is placed" }];
const fields = [{ id: "amount", label: "Amount", kind: "number" as const }];
const actionTypes = [{ id: "email", label: "Send an email", fields: [{ name: "to", label: "To", kind: "text" as const, required: true }] }];

const rule = ref<RuleDefinition | undefined>();
</script>

<template>
  <NqRuleBuilder v-model="rule" :events="events" :fields="fields" :action-types="actionTypes" />
</template>
```

### Blade

```blade
{{-- Pick the event, add conditions and actions; the sentence reads the rule back. --}}
<div class="w-[40rem] max-w-full">
    <x-nq::rule-builder :events="[['id' => 'order.created', 'label' => 'an order is placed']]" :fields="[['id' => 'amount', 'label' => 'Amount', 'kind' => 'number']]"
        :action-types="[['id' => 'email', 'label' => 'Send an email', 'fields' => [['name' => 'to', 'label' => 'To', 'kind' => 'text', 'required' => true]]]]" />
</div>
```

### HTML + Alpine

```html
<div class="w-[40rem] max-w-full">
    <div data-slot="rule-builder" x-data="nqRuleBuilder(JSON.parse('{\u0022events\u0022:[{\u0022id\u0022:\u0022order.created\u0022,\u0022label\u0022:\u0022an order is placed\u0022}],\u0022fields\u0022:[{\u0022id\u0022:\u0022amount\u0022,\u0022label\u0022:\u0022Amount\u0022,\u0022kind\u0022:\u0022number\u0022}],\u0022actionTypes\u0022:[{\u0022id\u0022:\u0022email\u0022,\u0022label\u0022:\u0022Send an email\u0022,\u0022fields\u0022:[{\u0022name\u0022:\u0022to\u0022,\u0022label\u0022:\u0022To\u0022,\u0022kind\u0022:\u0022text\u0022,\u0022required\u0022:true}]}],\u0022actionTypesFrom\u0022:null,\u0022value\u0022:null,\u0022maxDepth\u0022:3,\u0022disabled\u0022:false,\u0022t\u0022:{\u0022whenHelp\u0022:\u0022The event that starts the rule.\u0022,\u0022matchAll\u0022:\u0022All of these\u0022,\u0022matchAny\u0022:\u0022Any of these\u0022,\u0022groupLabel\u0022:\u0022Group: {join}\u0022,\u0022chooseField\u0022:\u0022Choose a field\u0022,\u0022yes\u0022:\u0022True\u0022,\u0022no\u0022:\u0022False\u0022,\u0022actionRow\u0022:\u0022Action {n}\u0022,\u0022problems\u0022:\u0022{n} to fix\u0022,\u0022issueEvent\u0022:\u0022Choose the event that starts the rule\u0022,\u0022issueActions\u0022:\u0022Add at least one action\u0022,\u0022issueField\u0022:\u0022A condition has no field\u0022,\u0022issueValue\u0022:\u0022A condition has no value\u0022,\u0022issueActionField\u0022:\u0022An action is missing \\u0022{field}\\u0022\u0022,\u0022sentence\u0022:{\u0022when\u0022:\u0022When {event}\u0022,\u0022ifWord\u0022:\u0022if\u0022,\u0022then\u0022:\u0022then\u0022,\u0022noConditions\u0022:\u0022always\u0022,\u0022and\u0022:\u0022and\u0022,\u0022or\u0022:\u0022or\u0022},\u0022ops\u0022:{\u0022is\u0022:\u0022is\u0022,\u0022isNot\u0022:\u0022is not\u0022,\u0022contains\u0022:\u0022contains\u0022,\u0022startsWith\u0022:\u0022starts with\u0022,\u0022isEmpty\u0022:\u0022is empty\u0022,\u0022isNotEmpty\u0022:\u0022is not empty\u0022,\u0022gt\u0022:\u0022is greater than\u0022,\u0022gte\u0022:\u0022is at least\u0022,\u0022lt\u0022:\u0022is less than\u0022,\u0022lte\u0022:\u0022is at most\u0022}}}'))" x-modelable="rule" class="flex min-w-0 flex-col gap-4">
    <section aria-label="This rule" data-slot="rule-summary" class="rounded-card border border-border bg-nq-surface-soft p-4">
        <p class="flex items-start gap-2 text-body text-foreground" aria-live="polite">
            <svg aria-hidden="true" class="mt-0.5 size-4 shrink-0 text-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M15.914 4a1.5 1.5 0 00-2.474-1.561l-9 9A1.5 1.5 0 005.5 14h4.002a.5.5 0 01.471.666L8.086 20a1.5 1.5 0 002.475 1.56l9-9A1.5 1.5 0 0018.5 10h-3.997a.5.5 0 01-.472-.667z"/>
</svg>            <span dir="auto" x-text="sentence()"></span>
        </p>
            </section>
    <div data-slot="alert" data-tone="warning" role="alert" x-show="messages().length" style="display: none"
        class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-warning/30 bg-nq-warning-soft">
        <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
            <div data-slot="alert-title" class="text-label text-foreground" x-text="problemsTitle()"></div>
            <div data-slot="alert-description" class="text-body-sm text-muted-foreground">
                <ul class="mt-1 list-disc ps-5 text-body-sm">
                    <template x-for="m in messages()" x-bind:key="m"><li x-text="m"></li></template>
                </ul>
            </div>
        </div>
    </div>
    <section aria-labelledby="nq-rule-000001-when" class="flex flex-col gap-2 rounded-card border border-border bg-card p-4">
        <div class="flex items-center gap-2">
            <span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-nq-brand/40 bg-[color-mix(in_oklab,var(--nq-brand)_14%,transparent)] text-foreground">1</span>
            <h3 id="nq-rule-000001-when" class="text-h4 text-foreground">When</h3>
        </div>
        <div data-slot="field" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     x-model="evInvalid" class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50 sr-only">When</label>
            <div data-slot="select" x-data="nqSelect(null, false)" x-modelable="value" x-id="['nq-select']" x-model="rule.event" class="contents">
    <button data-slot="select-trigger" x-ref="trigger" x-bind="trigger"
        aria-label="When" x-bind:disabled="disabled" class="flex h-control w-full min-w-0 items-center justify-between gap-2 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] cursor-default select-none outline-none transition-colors duration-150 ease-nq focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-popup-open:border-nq-focus data-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px]">
    <span data-slot="select-value" x-text="label() ?? 'Choose an event'" :data-placeholder="empty() ? '' : undefined"
    class="min-w-0 flex-1 truncate text-start data-placeholder:text-muted-foreground"></span>
    <span class="flex shrink-0 text-muted-foreground [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></span>
</button>
                <template x-teleport="body">
    <div data-slot="select-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.trigger"
        class="z-50 min-w-[var(--anchor-width)] max-h-[var(--available-height)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="select-item" x-bind="item('order.created', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('order.created')" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">an order is placed</span>
</div>
    </div>
</template>
    </div>
            <p data-slot="field-description" x-text="eventHelp()" class="text-caption text-muted-foreground">The event that starts the rule.</p>
</div>
    </section>
    <section aria-labelledby="nq-rule-000001-if" class="flex flex-col gap-2 rounded-card border border-border bg-card p-4">
        <div class="flex items-center gap-2">
            <span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-nq-brand/40 bg-[color-mix(in_oklab,var(--nq-brand)_14%,transparent)] text-foreground">2</span>
            <h3 id="nq-rule-000001-if" class="text-h4 text-foreground">If</h3>
            <span class="text-caption text-muted-foreground tabular-nums" x-text="conditionCount()">0</span>
        </div>
        <p class="text-body-sm text-muted-foreground">Only continue when these conditions hold. Leave empty to always continue.</p>
        <div x-bind:data-group="rule.conditions.id" role="group" x-bind:aria-label="groupLabel(rule.conditions)"
    class="flex flex-col gap-3 rounded-control border border-border p-3 ">
    <div class="flex flex-wrap items-center gap-2">
        <span class="text-label text-muted-foreground">Match</span>
        <div role="group" data-slot="toggle-group" data-variant="segmented" data-orientation="horizontal" aria-label="Match" x-bind:data-disabled="disabled ? '' : null"
            class="flex w-fit max-w-full gap-0.5 rounded-control bg-secondary p-0.5">
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="rule.conditions.join === 'and' ? 'true' : 'false'" x-bind:data-pressed="rule.conditions.join === 'and' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(rule.conditions, 'and')">All of these</button>
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="rule.conditions.join === 'or' ? 'true' : 'false'" x-bind:data-pressed="rule.conditions.join === 'or' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(rule.conditions, 'or')">Any of these</button>
        </div>
            </div>
    <p class="text-body-sm text-muted-foreground" x-show="rule.conditions.children.length === 0" style="display: none">No conditions: the rule always continues.</p>
    <ul class="flex flex-col gap-3">
        <template x-for="n1 in rule.conditions.children" x-bind:key="n1.id">
            <li x-bind:data-condition="n1.kind === 'condition' ? n1.id : null"
                x-bind:class="n1.kind === 'condition' ? 'grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,10rem)_minmax(0,1fr)_auto]' : ''">
                <template x-if="n1.kind === 'group'">
                    <div>
                                                    <div x-bind:data-group="n1.id" role="group" x-bind:aria-label="groupLabel(n1)"
    class="flex flex-col gap-3 rounded-control border border-border p-3 bg-nq-surface-soft">
    <div class="flex flex-wrap items-center gap-2">
        <span class="text-label text-muted-foreground">Match</span>
        <div role="group" data-slot="toggle-group" data-variant="segmented" data-orientation="horizontal" aria-label="Match" x-bind:data-disabled="disabled ? '' : null"
            class="flex w-fit max-w-full gap-0.5 rounded-control bg-secondary p-0.5">
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="n1.join === 'and' ? 'true' : 'false'" x-bind:data-pressed="n1.join === 'and' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(n1, 'and')">All of these</button>
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="n1.join === 'or' ? 'true' : 'false'" x-bind:data-pressed="n1.join === 'or' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(n1, 'or')">Any of these</button>
        </div>
                    <button data-slot="button"
     type="button"                         x-on:click="removeNode(n1.id)" x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control-sm px-2.5 ms-auto">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg>                Remove group</button>
            </div>
    <p class="text-body-sm text-muted-foreground" x-show="n1.children.length === 0" style="display: none">No conditions: the rule always continues.</p>
    <ul class="flex flex-col gap-3">
        <template x-for="n2 in n1.children" x-bind:key="n2.id">
            <li x-bind:data-condition="n2.kind === 'condition' ? n2.id : null"
                x-bind:class="n2.kind === 'condition' ? 'grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,10rem)_minmax(0,1fr)_auto]' : ''">
                <template x-if="n2.kind === 'group'">
                    <div>
                                                    <div x-bind:data-group="n2.id" role="group" x-bind:aria-label="groupLabel(n2)"
    class="flex flex-col gap-3 rounded-control border border-border p-3 bg-nq-surface-soft">
    <div class="flex flex-wrap items-center gap-2">
        <span class="text-label text-muted-foreground">Match</span>
        <div role="group" data-slot="toggle-group" data-variant="segmented" data-orientation="horizontal" aria-label="Match" x-bind:data-disabled="disabled ? '' : null"
            class="flex w-fit max-w-full gap-0.5 rounded-control bg-secondary p-0.5">
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="n2.join === 'and' ? 'true' : 'false'" x-bind:data-pressed="n2.join === 'and' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(n2, 'and')">All of these</button>
            <button type="button" data-slot="toggle" class="inline-flex h-7 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-3 text-label text-muted-foreground outline-none transition-colors duration-150 ease-nq hover:text-foreground [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:pointer-events-none data-disabled:opacity-50 rounded-[calc(var(--radius-control)-2px)] data-pressed:bg-card data-pressed:text-foreground data-pressed:shadow-xs" x-bind:aria-pressed="n2.join === 'or' ? 'true' : 'false'" x-bind:data-pressed="n2.join === 'or' ? '' : null"
                x-bind:disabled="disabled" x-bind:data-disabled="disabled ? '' : null" x-on:click="setJoin(n2, 'or')">Any of these</button>
        </div>
                    <button data-slot="button"
     type="button"                         x-on:click="removeNode(n2.id)" x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control-sm px-2.5 ms-auto">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg>                Remove group</button>
            </div>
    <p class="text-body-sm text-muted-foreground" x-show="n2.children.length === 0" style="display: none">No conditions: the rule always continues.</p>
    <ul class="flex flex-col gap-3">
        <template x-for="n3 in n2.children" x-bind:key="n3.id">
            <li x-bind:data-condition="n3.kind === 'condition' ? n3.id : null"
                x-bind:class="n3.kind === 'condition' ? 'grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,10rem)_minmax(0,1fr)_auto]' : ''">
                <template x-if="n3.kind === 'group'">
                    <div>
                                            </div>
                </template>
                <template x-if="n3.kind === 'condition'">
                    <div class="contents">
                        <select data-slot="select" aria-label="Field" x-bind:disabled="disabled" x-bind:data-invalid="bad(n3, 'no-field') ? '' : null"
                            x-bind:aria-invalid="bad(n3, 'no-field') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="setField(n3, $event.target.value)">
                            <option value="" x-bind:selected="! n3.field">Choose a field</option>
                            <template x-for="f in fields" x-bind:key="f.id"><option x-bind:value="f.id" x-bind:selected="f.id === n3.field" x-text="f.label"></option></template>
                        </select>
                        <button data-slot="button"
     type="button"                         aria-label="Remove condition" title="Remove condition" x-on:click="removeNode(n3.id)" x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 sm:order-last">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg></button>
                        <select data-slot="select" aria-label="Operator" x-bind:disabled="disabled || ! n3.field" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control col-span-2 sm:col-span-1"
                            x-on:change="n3.op = $event.target.value">
                            <template x-for="o in ops(n3)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n3.op" x-text="o.label"></option></template>
                        </select>
                        <div class="col-span-2 min-w-0 sm:col-span-1">
                            <template x-if="! unary(n3) && isChoice(n3)">
                                <select data-slot="select" aria-label="Value" x-bind:disabled="disabled" x-bind:data-invalid="bad(n3, 'no-value') ? '' : null"
                                    x-bind:aria-invalid="bad(n3, 'no-value') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="n3.value = $event.target.value">
                                    <option value="" x-bind:selected="! n3.value"></option>
                                    <template x-for="o in choices(n3)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n3.value" x-text="o.label"></option></template>
                                </select>
                            </template>
                            <template x-if="! unary(n3) && ! isChoice(n3)">
                                <input data-slot="input" aria-label="Value" x-bind:type="isNumber(n3) ? 'number' : 'text'" x-bind:inputmode="isNumber(n3) ? 'decimal' : null"
                                    x-bind:dir="isNumber(n3) ? 'ltr' : null" x-bind:disabled="disabled" x-bind:aria-invalid="bad(n3, 'no-value') ? 'true' : null"
                                    x-bind:data-invalid="bad(n3, 'no-value') ? '' : null" x-bind:value="n3.value" x-on:input="n3.value = $event.target.value" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
                            </template>
                        </div>
                    </div>
                </template>
            </li>
        </template>
    </ul>
    <div class="flex flex-wrap gap-2">
        <button data-slot="button"
     type="button"                         x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" x-on:click="addCondition(n2)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>            Add condition</button>
            </div>
</div>
                                            </div>
                </template>
                <template x-if="n2.kind === 'condition'">
                    <div class="contents">
                        <select data-slot="select" aria-label="Field" x-bind:disabled="disabled" x-bind:data-invalid="bad(n2, 'no-field') ? '' : null"
                            x-bind:aria-invalid="bad(n2, 'no-field') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="setField(n2, $event.target.value)">
                            <option value="" x-bind:selected="! n2.field">Choose a field</option>
                            <template x-for="f in fields" x-bind:key="f.id"><option x-bind:value="f.id" x-bind:selected="f.id === n2.field" x-text="f.label"></option></template>
                        </select>
                        <button data-slot="button"
     type="button"                         aria-label="Remove condition" title="Remove condition" x-on:click="removeNode(n2.id)" x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 sm:order-last">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg></button>
                        <select data-slot="select" aria-label="Operator" x-bind:disabled="disabled || ! n2.field" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control col-span-2 sm:col-span-1"
                            x-on:change="n2.op = $event.target.value">
                            <template x-for="o in ops(n2)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n2.op" x-text="o.label"></option></template>
                        </select>
                        <div class="col-span-2 min-w-0 sm:col-span-1">
                            <template x-if="! unary(n2) && isChoice(n2)">
                                <select data-slot="select" aria-label="Value" x-bind:disabled="disabled" x-bind:data-invalid="bad(n2, 'no-value') ? '' : null"
                                    x-bind:aria-invalid="bad(n2, 'no-value') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="n2.value = $event.target.value">
                                    <option value="" x-bind:selected="! n2.value"></option>
                                    <template x-for="o in choices(n2)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n2.value" x-text="o.label"></option></template>
                                </select>
                            </template>
                            <template x-if="! unary(n2) && ! isChoice(n2)">
                                <input data-slot="input" aria-label="Value" x-bind:type="isNumber(n2) ? 'number' : 'text'" x-bind:inputmode="isNumber(n2) ? 'decimal' : null"
                                    x-bind:dir="isNumber(n2) ? 'ltr' : null" x-bind:disabled="disabled" x-bind:aria-invalid="bad(n2, 'no-value') ? 'true' : null"
                                    x-bind:data-invalid="bad(n2, 'no-value') ? '' : null" x-bind:value="n2.value" x-on:input="n2.value = $event.target.value" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
                            </template>
                        </div>
                    </div>
                </template>
            </li>
        </template>
    </ul>
    <div class="flex flex-wrap gap-2">
        <button data-slot="button"
     type="button"                         x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" x-on:click="addCondition(n1)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>            Add condition</button>
                    <button data-slot="button"
     type="button"                         x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" x-on:click="addGroup(n1)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>                Add group</button>
            </div>
</div>
                                            </div>
                </template>
                <template x-if="n1.kind === 'condition'">
                    <div class="contents">
                        <select data-slot="select" aria-label="Field" x-bind:disabled="disabled" x-bind:data-invalid="bad(n1, 'no-field') ? '' : null"
                            x-bind:aria-invalid="bad(n1, 'no-field') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="setField(n1, $event.target.value)">
                            <option value="" x-bind:selected="! n1.field">Choose a field</option>
                            <template x-for="f in fields" x-bind:key="f.id"><option x-bind:value="f.id" x-bind:selected="f.id === n1.field" x-text="f.label"></option></template>
                        </select>
                        <button data-slot="button"
     type="button"                         aria-label="Remove condition" title="Remove condition" x-on:click="removeNode(n1.id)" x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 sm:order-last">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg></button>
                        <select data-slot="select" aria-label="Operator" x-bind:disabled="disabled || ! n1.field" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control col-span-2 sm:col-span-1"
                            x-on:change="n1.op = $event.target.value">
                            <template x-for="o in ops(n1)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n1.op" x-text="o.label"></option></template>
                        </select>
                        <div class="col-span-2 min-w-0 sm:col-span-1">
                            <template x-if="! unary(n1) && isChoice(n1)">
                                <select data-slot="select" aria-label="Value" x-bind:disabled="disabled" x-bind:data-invalid="bad(n1, 'no-value') ? '' : null"
                                    x-bind:aria-invalid="bad(n1, 'no-value') ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-on:change="n1.value = $event.target.value">
                                    <option value="" x-bind:selected="! n1.value"></option>
                                    <template x-for="o in choices(n1)" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === n1.value" x-text="o.label"></option></template>
                                </select>
                            </template>
                            <template x-if="! unary(n1) && ! isChoice(n1)">
                                <input data-slot="input" aria-label="Value" x-bind:type="isNumber(n1) ? 'number' : 'text'" x-bind:inputmode="isNumber(n1) ? 'decimal' : null"
                                    x-bind:dir="isNumber(n1) ? 'ltr' : null" x-bind:disabled="disabled" x-bind:aria-invalid="bad(n1, 'no-value') ? 'true' : null"
                                    x-bind:data-invalid="bad(n1, 'no-value') ? '' : null" x-bind:value="n1.value" x-on:input="n1.value = $event.target.value" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
                            </template>
                        </div>
                    </div>
                </template>
            </li>
        </template>
    </ul>
    <div class="flex flex-wrap gap-2">
        <button data-slot="button"
     type="button"                         x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" x-on:click="addCondition(rule.conditions)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>            Add condition</button>
                    <button data-slot="button"
     type="button"                         x-bind:disabled="disabled" x-bind:data-disabled="disabled ? &#039;&#039; : null" x-on:click="addGroup(rule.conditions)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>                Add group</button>
            </div>
</div>
    </section>
    <section aria-labelledby="nq-rule-000001-then" class="flex flex-col gap-2 rounded-card border border-border bg-card p-4">
        <div class="flex items-center gap-2">
            <span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-nq-brand/40 bg-[color-mix(in_oklab,var(--nq-brand)_14%,transparent)] text-foreground">3</span>
            <h3 id="nq-rule-000001-then" class="text-h4 text-foreground">Then</h3>
        </div>
        <p class="text-body-sm text-muted-foreground">What to do, in order.</p>
        <div data-slot="repeater" x-data="nqRepeater([], Object.assign(JSON.parse('{\u0022duplicable\u0022:false,\u0022collapsible\u0022:false}'), { createItem: () => (newAction()), rowTitle: (item, index) => (actionTitle(item, index)), rowLabel: (item, index) => (actionTitle(item, index)) }))" x-modelable="items" x-id="['nq-repeater-body']"     x-model="rule.actions" class="flex min-w-0 flex-col gap-3">
                <p :id="hintId()" class="sr-only">Focus the handle, then use the arrow keys to move the row. Home and End jump to the ends.</p>
    <div x-show="count() === 0" x-cloak style="display: none" data-slot="repeater-empty"
        class="rounded-card border border-dashed border-border px-4 py-6 text-center text-body-sm text-muted-foreground">
        <p class="text-body-sm text-muted-foreground">No actions yet.</p>    </div>
    <ol x-show="count() > 0" x-cloak style="display: none" aria-label="Actions" class="flex flex-col gap-2">
        <template x-for="(item, index) in items" :key="keyOf(index)">
            <li data-slot="repeater-row" :data-row-key="keyOf(index)" :data-collapsed="isCollapsed(index) ? 'true' : undefined" :data-dragging="isDragging(index) ? 'true' : undefined" :style="rowStyle(index)"
                class="relative rounded-card border border-border bg-card data-dragging:z-10 data-dragging:border-nq-focus data-dragging:shadow-floating">
                <div data-slot="repeater-row-header" class="flex min-h-control items-center gap-1 p-1.5">
                                            <button type="button" x-show="count() > 1" data-repeater-focus :aria-label="$nq.t('Reorder ' + name(index), 'إعادة ترتيب ' + name(index))" :title="$nq.t('Reorder ' + name(index), 'إعادة ترتيب ' + name(index))"
                            :aria-describedby="hintId()" aria-keyshortcuts="ArrowUp ArrowDown Home End" :disabled="disabled"
                            x-on:keydown="onHandleKey($event, index)" x-on:pointerdown="startDrag($event, index)"
                            class="inline-flex size-control-sm shrink-0 cursor-grab touch-none items-center justify-center rounded-control text-muted-foreground outline-none hover:bg-nq-hover hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus active:cursor-grabbing disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4">
                            <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="9" cy="12" r="1"/>
  <circle cx="9" cy="5" r="1"/>
  <circle cx="9" cy="19" r="1"/>
  <circle cx="15" cy="12" r="1"/>
  <circle cx="15" cy="5" r="1"/>
  <circle cx="15" cy="19" r="1"/>
</svg>                        </button>
                                                                <div class="flex min-w-0 flex-1 items-center gap-2 px-1.5">
                            <span  class="min-w-0 truncate text-label text-foreground outline-none" x-text="title(index)"></span>
                        </div>
                                        <span class="sr-only" x-text="n(index + 1)"></span>
                                        <button data-slot="button"
     type="button"                         :aria-label="$nq.t(&#039;Remove &#039; + name(index), &#039;حذف &#039; + name(index))" :title="$nq.t(&#039;Remove &#039; + name(index), &#039;حذف &#039; + name(index))" :disabled="disabled || atMin()" x-on:click="remove(index)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:bg-nq-hover size-control-sm p-0 text-muted-foreground hover:text-nq-danger-text">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg></button>
                </div>
                <div :id="$id('nq-repeater-body', index)" data-slot="repeater-body" x-show="!isCollapsed(index)" class="border-t border-border p-3 sm:p-4"><div class="flex flex-col gap-4">
                <div data-slot="field" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Action</label>
                    <div data-slot="select" x-data="nqSelect(null, false)" x-modelable="value" x-id="['nq-select']" x-model="item.type" class="contents">
    <button data-slot="select-trigger" x-ref="trigger" x-bind="trigger"
        aria-label="Action" x-bind:disabled="disabled" class="flex h-control w-full min-w-0 items-center justify-between gap-2 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] cursor-default select-none outline-none transition-colors duration-150 ease-nq focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-popup-open:border-nq-focus data-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px]">
    <span data-slot="select-value" x-text="label() ?? 'Choose an action'" :data-placeholder="empty() ? '' : undefined"
    class="min-w-0 flex-1 truncate text-start data-placeholder:text-muted-foreground"></span>
    <span class="flex shrink-0 text-muted-foreground [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></span>
</button>
                        <template x-teleport="body">
    <div data-slot="select-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.trigger"
        class="z-50 min-w-[var(--anchor-width)] max-h-[var(--available-height)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="select-item" x-bind="item('email', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('email')" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">Send an email</span>
</div>
    </div>
</template>
    </div>
                    <p data-slot="field-description" x-show="actionDescription(item)" style="display: none" x-text="actionDescription(item)" class="text-caption text-muted-foreground"></p>
</div>
                <template x-for="f in actionFields(item)" x-bind:key="f.name">
                    <div>
                        <template x-if="f.isBool">
                            <div class="flex flex-row items-center justify-between gap-3">
                                <div class="min-w-0">
                                    <span class="text-label text-foreground" x-text="f.label"></span>
                                    <p class="text-caption text-muted-foreground" x-show="f.help !== ''" style="display: none" x-text="f.help"></p>
                                </div>
                                <button type="button" role="switch" data-slot="switch" x-data="nqSwitch(false)" x-modelable="checked" x-bind="root"
    aria-checked="false"
     data-unchecked                 x-model="item.config[f.name]" x-bind:aria-label="f.label" class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent bg-nq-line-strong p-0.5 outline-none transition-colors duration-150 ease-nq data-checked:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50">
    <span data-slot="switch-thumb"  data-unchecked         x-bind:data-checked="checked ? '' : undefined" x-bind:data-unchecked="checked ? undefined : ''"
        class="block size-4 rounded-full bg-background shadow-xs data-checked:bg-primary-foreground transition-[translate] duration-150 ease-nq data-checked:translate-x-3.5 rtl:data-checked:-translate-x-3.5"></span>
    </button>
                            </div>
                        </template>
                        <template x-if="! f.isBool">
                            <div class="flex flex-col gap-1.5" x-bind:data-invalid="f.invalid ? '' : null">
                                <label class="text-label text-foreground">
                                    <span x-text="f.label"></span>
                                    <span x-show="f.required" style="display: none" aria-hidden="true" class="ms-1 text-nq-danger-text">*</span>
                                </label>
                                <template x-if="f.isSelect">
                                    <select data-slot="select" x-bind:aria-label="f.label" x-bind:disabled="disabled" x-bind:aria-invalid="f.invalid ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control"
                                        x-on:change="setConfig(item, f.name, $event.target.value)">
                                        <option value="" x-bind:selected="f.text === ''" x-text="f.placeholder"></option>
                                        <template x-for="o in f.options" x-bind:key="o.value"><option x-bind:value="o.value" x-bind:selected="o.value === f.text" x-text="o.label"></option></template>
                                    </select>
                                </template>
                                <template x-if="f.isArea">
                                    <textarea data-slot="textarea" x-bind:rows="f.isCode ? 5 : 3" x-bind:dir="f.isCode ? 'ltr' : null" x-bind:spellcheck="f.isCode ? 'false' : null" x-bind:placeholder="f.placeholder"
                                        x-bind:disabled="disabled" x-bind:aria-invalid="f.invalid ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] min-h-20 py-2" x-bind:class="f.isCode ? 'font-mono text-caption' : ''"
                                        x-bind:value="f.text" x-on:input="setConfig(item, f.name, $event.target.value)"></textarea>
                                </template>
                                <template x-if="f.isInput">
                                    <input data-slot="input" x-bind:type="f.inputType" x-bind:inputmode="f.inputMode || null" x-bind:dir="f.ltr ? 'ltr' : null" x-bind:placeholder="f.placeholder"
                                        x-bind:disabled="disabled" x-bind:aria-invalid="f.invalid ? 'true' : null" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control" x-bind:value="f.text"
                                        x-on:input="setConfig(item, f.name, $event.target.value, f.kind)">
                                </template>
                                <p class="text-caption text-muted-foreground" x-show="f.help !== ''" style="display: none" x-text="f.help"></p>
                                <div role="alert" class="text-caption text-nq-danger-text" x-show="f.invalid" style="display: none">Required</div>
                            </div>
                        </template>
                    </div>
                </template>
            </div></div>
            </li>
        </template>
    </ol>
    <div class="flex flex-wrap items-center gap-3">
        <button data-slot="button"
     type="button"                         data-repeater-add="data-repeater-add" :disabled="disabled || atMax()" :aria-describedby="limitText() ? limitId() : undefined" x-on:click="add()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>            Add action</button>
        <span x-show="limitText()" x-cloak style="display: none" :id="limitId()" class="text-caption text-muted-foreground" x-text="limitText()"></span>
    </div>
    <div aria-live="polite" role="status" class="sr-only" x-text="announcement"></div>
</div>
    </section>
</div>
</div>
```
