This release lands Theme Builder v2 — a full three-column rebuild with variations, schema-driven settings, and macOS-style browser-chrome previews — and replaces the legacy Rules engine with a schema-driven Conditions system that powers every condition
surface in the admin and runtime.
It also brings multi-environment safety to publish/edit flows, sliding-indicator animation to tab navigation, and a broad UI consistency pass across settings tables, list headers, and content detail chrome.
What's Changed
🎨 Theme Builder v2
- Rebuilt the theme builder as a three-column shell with variations on the left, schema-driven settings in the right inspector, and a live macOS-chrome preview in the middle.
- Added variations support with drag-to-reorder, inline rename, conditions, and Base pinning.
- Replaced the legacy v1 inspector with schema-driven field components (typed FieldDef schema, cascade rules, coverage-tested round-trip).
- Restored per-setting tooltips on every inspector field with full i18n in en-US and zh-Hans.
- Added preview-frame chrome (browser bar + widget switcher) so widgets keep their intended layout context.
- Added unsaved-changes warning on close and pre-publish readonly + validation guards.
- Theme detail now lives inside the shared sidebar shell, matching the rest of the admin's detail-page architecture.
- New variations seed from the current Base settings rather than factory defaults.
- Polished active color swatch labels, font-color positioning, Auto fallback rendering, primary brand color seeding, banner alignment in chrome, and many smaller details.
🧱 Conditions (schema-driven replacement for Rules)
- Replaced v1 Rules with a schema-driven Conditions system covering every condition type (user-attr, current-page, event, event-attribute, segment, content, element, text-input, text-fill, time, task-clicked, group).
- Migrated every Rules consumer in the admin and shared editor to the new component; deleted v1 Rules from shared-components.
- Added a Where-clause UI for event filters with errors that bubble up to the outer event chip and a [Where] badge that distinguishes it from [If].
- Added standalone exports for Frequency, IfCompleted, Wait, and Priority that reuse the same primitives.
- Validation now spans snapshot, property-based, and production-fixture tests.
📅 Conditions polish
- Date attributes now render in the chip as MMM d, yyyy, matching the picker trigger.
- Split absolute-date operator labels into separate dropdown vs chip forms so "Signed up on May 13, 2026" reads naturally.
- Inline the two range inputs for between on a single row.
- Keep "Add value" alive when list-attribute popovers reopen, and hide stale list values on valueless operators (is empty / has any value).
- Commit invalid edits on popover close so the save gate catches them; block save when checklist / resource center conditions are incomplete.
- Honor the consumer's filterItems array order in the add-condition dropdown.
- The DateTimePicker calendar now sits above its parent popover (no more z-index clipping in builder chrome) and matches the conditions-popover trigger hover language.
- Say "Add filter" instead of "Add condition" when the same component is used to filter a list (segments, user/company tables).
✨ Tabs & UI animation
- Replaced the instant data-state styling on Tabs with a shared motion.span that slides between triggers via framer-motion's layoutId. Pill and underline variants both ride the same mechanism.
- Added a variant="primary" cva variant for tinted active pills (replaces six call sites that hand-rolled data-[state=active]:bg-primary overrides).
- The content detail header's underline now slides between Analytics / Content / Versions on route change.
🛡️ Multi-environment safety
- useContentBuilder and the rename / open-editor form now decide whether to fork using contentOnEnvironments (per-env source of truth) instead of the deprecated Content.publishedVersionId field. Resolves a class of bugs where a publish in one
environment could send authors straight into a still-live version in another. - Session status badges flip to terminal-first priority (Dismissed > Completed > Active) so a session that was completed and then dismissed reads as Dismissed, matching the underlying event log.
- "Finished in X" wording in session lists aligned to "Completed in X" to match the canonical FLOW_COMPLETED event name.
- Removed the "Published X ago" badge from the content detail header — per-env publish times don't reduce to one number, and version history surfaces the detail when needed.
📋 Settings & list cleanup
- Dropped the CreatedAt column from Attributes / Events / Environments settings tables. API keys keep it because creation time is a real security / rotation signal.
- Unified the eight "New X" buttons across settings and content lists onto a single RiAddLine + mr-2 h-4 w-4 pattern. Fixed New Events → New Event along the way.
- Segment headers now use horizontal dots (matching page-level overflow conventions elsewhere).
🔧 Fixes & refactors
- Fixed analytics: NPS / Scale response-rate denominator now aligns with the rolling-window aggregate.
- Fixed resource center: active session resumes on refresh regardless of current page; attrCodes preloaded from action-block clickedActions.
- Fixed content loading spinner to center reliably inside detail pages' min-h-full containers via a min-h-[60vh] floor.
- Extracted CompactPopoverTrigger to consolidate three identical inline trigger className chains (ConditionCombobox, ConditionSelect, DateTimePicker).
- Several i18n polishes across theme-builder option labels ("Dismiss the flow", "Show a speech bubble instead"), DateTime operator phrasing, dead placement keys, etc.
- Build / typecheck: exported forwardRef prop interfaces so tsup --dts can emit valid declarations; aligned border.borderRadius type to number.
Full Changelog: v0.7.1...v0.7.2