The ConditionEditor components lay out editable condition rows — a card per condition holding the controls that edit it, joined to the rows around it by their operator.
ConditionEditorItem for one editable condition row, stacked in a ConditionEditor. Use ConditionViewerItem instead when the condition is read-only.header/headerActions/footer around them. The controls inside those (the All/Any match, add-condition/add-group, duplicate/remove group) and drag-and-drop behavior belong to the application.header, its own duplicate/remove in headerActions, and add-condition/add-group in the set's footer. Do not render your own header or footer row beside a ConditionEditor.operator labels between its rows read-only (no operatorOptions); the header is the one place to change it.InlineStack or Stack.details.actions, not among the controls.footer for one short line at the foot of the card, such as an example of what the condition matches ("e.g. Ada Lovelace’s plan is pro") or a link. Compose it yourself (Text text="product-pxs" color="secondary", Link); Pluma styles nothing in it. Do not put errors there.heading to name what kind of condition a row is ("Object attribute"), optionally with its Icon in a sm Coin. Leave the Coin's default gray; don't color-code kinds. Derive it from the selected field; do not add a separate type Select when the field picker already covers every kind.operator on every row after the first, as plain sentence-case text ("And", "Or"). Leave it unset on the first row, and do not pass a Badge yourself.operatorOptions and onOperatorChange; Pluma renders a small SegmentedControl. Do not render your own Select, menu or tag on the connector.header (All / Any), with read-only operators between rows. Never make one row's operator switchable and have later rows follow it. Per-row controls are fine on any rows where each operator is independent; each changes its own row only, and a set that mixes operators should nest the tighter part.header, use a small SegmentedControl named "Group operator", not a Select: a choice of two shows both.ConditionEditor inside an item. There is no nesting prop. Do not draw your own group border or background.surface-content, set the connectorSurfaceColor CSS variable to that background.className or inline styles. Use the public CSS variables exported from @customerio/pluma-components/css.withCenterBaseline or wrap controls in CenterBaseline.CenterBaseline so it lines up with the controls.withHandle to render the reorder button; isHandleDisabled disables it. It does not drag on its own: pass handleRef and give the element to a drag-and-drop library. In React, any ref works (dnd-kit's handleRef directly). In Ember, pass a callback that receives the button, or null when it's removed. Do not render a handle button yourself.hasHeadingBlock, hasDetailsBlock, hasFooterBlock and hasActionsBlock (and hasHeaderBlock, hasHeaderActionsBlock, hasFooterBlock on ConditionEditor).connectorPosition unset when items render as siblings. In a virtualized list, set it on every item (first/middle/last by index in the whole set, only for a set of one).ariaLabel or label); a row has no visible labels. A heading names the row's controls as a group but does not replace each control's own name.aria-label that names the action ("Remove condition").header is a group named by it; don't add role or aria-labelledby yourself. Name the header's controls ("Group operator").