Dynamic values: TUI visual refresh (modal, SearchSelect picker, pills) - #89
Dynamic values: TUI visual refresh (modal, SearchSelect picker, pills)#89juliacanzani wants to merge 7 commits into
Conversation
Reskin only — the ProseMirror mechanics, settings state machine, and token format are untouched. - Settings modal: react-aria overlay shell -> TUI Modal (portalled into a context-classed container so tf-context-* theming still applies); bespoke unstyled radios/input -> RadioGroup + Field/TextInput; the value picker is TUI's new SearchSelect (button trigger showing the bolt + category + label pill, transient search panel, grouped list) - Inline chip (ProseMirror node view): tokenised styles (TUI primary scale with the old indigo as fallbacks) and a currentColor SVG bolt instead of the emoji; forced-colors outline; pill styles moved to a shared partial (replace-mode fields never loaded the editor styles) - Replace mode: the disabled-input-with-label becomes a dynamic-value pill on a tinted input-shaped bar; the insert/clear icon buttons use mask-based TUI icons that follow currentColor (the old base64 bolt was baked dark and vanished in dark contexts; the clear was a text glyph pseudo-element) - TangibleUI: bump to ^0.2.9 (SearchSelect + shared listbox engine) - jest: dynamic render tests updated for the TUI modal chrome (.tui-modal container, backdrop dismissal, SearchSelect picker) — 506 passing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-ups from Julia's review of the first reskin pass: - Insert/clear affordances are TUI IconButtons (ghost/secondary) sitting in tui-input-group suffix APPEND slots — field + affordances read as one control. The floating absolutely-positioned buttons, their mask pseudo-elements, and the editor's 25px padding compensations are gone. - Replace mode no longer opens the popover-with-a-combobox (the 'weird double dropdown'): the bolt IconButton opens TUI SearchSelect directly, anchored under the whole field, via the new external-trigger mode (anchorRef/restoreFocusRef, @tangible/ui 0.2.10). Values that declare settings still route to the legacy settings popover after picking. - BaseWrapper's ComboBox picking branch removed; the popover now exists solely for per-value settings forms. - TangibleUI: bump to ^0.2.10. - jest: role-based queries for the icon-button affordances, SearchSelect panel recognised as the picker container — 506 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Second pass per Julia's review: insert/clear are now ghost/secondary TUI IconButtons in input-group suffix append slots (no more floating buttons or mask pseudo-elements), and replace mode's bolt opens the SearchSelect panel directly anchored under the field — the popover-with-a-combobox double dropdown is gone. Uses |
…l; editable replace input
Three review notes from Julia:
- The bolt-plus now ALWAYS opens the SearchSelect insert panel — in the
editor too, which previously jumped straight to the settings modal.
The modal is reserved for editing (kebab/double-click) and for picked
values that declare settings, where it opens prefilled with the picked
value and its settings sub-form.
- The legacy inline settings popover ('the old modal' look) is gone
entirely — BaseWrapper routes settings values to the same
DynamicFieldSettings modal, and its react-aria overlay machinery,
Control/Title rendering, and popover styles are deleted. The grouped
choice list is now built once in dynamic/choices.ts, shared by the
editor, BaseWrapper, and the modal.
- Replace mode's static input is editable until a dynamic value
overrides it (was hard-coded readOnly).
506 jest tests passing; all flows re-verified live (insert→panel→inline
pill, settings value→prefilled modal in both modes, zero legacy popover,
static typing in replace mode).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Third pass: the bolt-plus always opens the SearchSelect insert panel (editor included — it previously jumped straight to the settings modal); the settings modal now only appears for editing and for picked values that declare settings, prefilled. The legacy inline settings popover is deleted entirely (BaseWrapper routes to the same modal), and replace mode's static input is editable until a dynamic value overrides it. Choice-list building is deduplicated into |
- Custom key input works: TUI TextInput is a native wrapper (onChange, not onValueChange — the handler was silently falling into rest and the controlled input never updated; fields has no tsc gate to catch it) - The insert panel gains a 'Custom value…' row — with the bolt now always opening the panel there was no path to CREATE a custom key; the row opens the settings modal straight into custom mode (new defaultMode prop on DynamicFieldSettings) - Number/color/date use the slotted icon-button affordances too: FieldWrapper defaults to buttonType 'inside', and the group renders chrome-less around controls that own their borders (border/tint kept only for the text-replace input and the dynamic pill bar) - jest updated: clear affordance only shows once a dynamic value is set (was outside-mode's always-visible disabled Clear) — 506 passing Verified live: custom flow end to end (panel row → custom-mode modal → typing → token inserted), slotted bolts on number/color/date with no double chrome. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three stacked height bugs, all measured live: - Appended IconButtons scale WITH the host control: one visual step down (control minus group padding/border, 40 -> 30), clamped to the 24px WCAG target floor. Styled rather than a fixed t-shirt size so context control-height remaps (Elementor's 28px md) can't overflow the group — sm's 32px was stretching 40px groups to 42px. - The pill display no longer stacks its own min-height/padding on the group's (40 -> 48); the group owns the control height. - Single-line editor: .tf-dt-line stays display:block — forcing it inline made ProseMirror's trailing <br> a second line box, so an EMPTY editor was 48px and jumped to 24px on the first keystroke. Empty and typed both sit at 40px now. Verified: static input group 40, dynamic pill bar 40, editor empty/typed 40, chrome-less composed groups 40, appended buttons 30. 506 jest green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pill margins for breathing room in the editor line, larger bolt glyph (1.25em), selected-pill outline on the focus-ring tokens, append-slot inline inset, tidier in-group display reset.
The plain paths sized correctly but dynamic: true silently locked fields to md. Now: - Text threads size into DynamicEditor; DynamicEditor accepts it, classes its input group (is-size-*), and forwards to FieldWrapper → BaseWrapper (which classes the tf-dynamic-group). Number/color/date already spread props into FieldWrapper, so their size flows for free. - The appended-affordance scale follows the ladder via a per-size --tf-dynamic-control on the group (sm 36→26, md 40→30, lg 48→38), still clamped at the 24px target floor and still tracking context height remaps. - Pill font/paddings ride the group's control font (em-based), so the replace bar scales with its tier. - New 'Sizes (sm/md/lg)' story covering insert + replace; jest asserts is-size-* lands on the group in both modes — 508 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What
The dynamic-values UI gets its TUI facelift — reskin only: the ProseMirror editor mechanics (click-to-select, backspace deletion, kebab/double-click edit, replace-on-type), the settings state machine (parse-on-open, delimiter stripping, settingsRef), and the
[[type::key=value]]token format are all untouched.Pairs with
@tangible/ui@0.2.9, which shipped SearchSelect (tangible-ui#81) — the transient-search picker built for exactly this dropdown.The pieces
Settings modal — the react-aria overlay shell becomes TUI
Modal(portalled into a context-classed container sotf-context-*theming still applies inside the portal, same trick as the old wrapper). The body — previously bespoke native radios and a raw text input with zero CSS — is nowRadioGroup+Field/TextInput, and the value picker is SearchSelect: a select-shaped trigger showing the committed value as a bolt + Category + label pill, opening a searchable grouped panel (the design's "Choose dynamic value dropdown").Inline chip (ProseMirror node view) — markup unchanged; styles tokenised onto the TUI primary scale (old indigo hex kept as fallbacks, so nothing shifts until a context remaps), the ⚡ emoji swapped for a
currentColorSVG bolt, forced-colors support added. The pill styles moved to a shared partial — replace-mode fields never loaded the editor stylesheet they lived in.Replace mode — the disabled-text-input-showing-a-label becomes a dynamic-value pill on a tinted input-shaped bar. The insert/clear icon buttons swap their baked-dark base64 bolt (invisible in dark contexts) and text-glyph × for mask-based TUI icons that follow
currentColor.Verified
.tui-modalcontainer, backdrop dismissal, SearchSelect picker).assets/build/*).🤖 Generated with Claude Code