Skip to content

chore(deps): upgrade frappe-ui to 1.0.0-beta.55 - #752

Draft
NagariaHussain wants to merge 34 commits into
developfrom
feat/frappe-ui-beta55
Draft

chore(deps): upgrade frappe-ui to 1.0.0-beta.55#752
NagariaHussain wants to merge 34 commits into
developfrom
feat/frappe-ui-beta55

Conversation

@NagariaHussain

@NagariaHussain NagariaHussain commented Aug 27, 2026

Copy link
Copy Markdown
Member

Supersedes #747, which stopped at beta.45. Same branch point, more on top.

Why?

We were on frappe-ui@1.0.0-beta.25 (20 July) and the delta only grew. This
takes us to 1.0.0-beta.55 in two hops, and carries the UI work that the new
component APIs made possible.

What?

The upgrade (beta.25beta.45beta.55), with tiptap moved to
3.29.2 as a set. Breaking changes that reached us:

Kind Change
Loud frappe-ui/editor-style.css and frappe-ui/list-style.css exports removed — the barrels self-import their CSS now
Loud Autocomplete removed → MultiSelect in AssignDialog
Loud pageMetaPlugin removed
Silent Radius aliases removed. rounded-md emits no CSS at all — 113 renames over 29 files
Silent Chromatic ink scales shift one level. ink-gray does not shift — 33 renames over 11 files
Silent Tabs is a composed family and models the trigger value, not an index
Silent Dropdown ignores placement; menus quietly left-align
Silent PageHeaderMobile #left/#right#prefix/#suffix — Vue drops unknown slots without a word
Silent Combobox template ref exposes clear(), not reset()
Silent Badge dropped the orange theme → amber. An unrecognised theme renders no color classes at all
Silent SettingsDialog renamed its open model from modelValue to open

Callouts become a container node. The body was a markdown string in an
attribute, so the node view ran a second Editor and a hand-built B/I/Link
toolbar for three marks. It is now real document content, which hands the
callout every mark and block the main editor has: lists, headings, code
blocks, images, Cmd+K links, the bubble menu, undo history. The stored format
is unchanged, so no migration. The title is edited in place in the header row,
and Mod-Enter / ArrowDown / Backspace give an isolating node real exits.
Styling matches frappe-ui's Alert in the editor, on the public page, and in
print.

The space list becomes a feed. A four-column table that needed a
responsive override is now the list family's default feed row: avatar, name
over route, page count, status. Search, an All/Published/Unpublished filter
and a result tally share one row above a centered column. Two measure columns
join it — last updated (newest page edit, not the space's own modified) and
open change requests.

Git sync accepts an arbitrary branch name. The picker only offered what
GitHub listed, so a branch past the first page could not be chosen.
Autocomplete gains an allow-custom mode, and branch_exists asks GitHub
for the single branch instead of scanning the 100-capped repo_branches, so a
typo surfaces in the create dialog instead of failing the first sync.

Plus: theme swapping handed to frappe-ui (flash-free), the rounded card around
the content column dropped, and the list components moved onto the documented
frappe-ui/list recipe.

How?

Two codemod passes, both non-idempotent, landed with the version bump because
either half alone renders wrong:

  • tokens-v2 --radius-onlynot the plain codemod, whose color and
    typography passes already ran during the beta.25 upgrade
  • tokens-v2 --ink-shift, with its .tokens-v2-ink-shift markers committed so
    a fresh clone keeps the re-run guard

The six var(--ink-*) and three var(--radius-*) reads in hand-written CSS
are migrated by hand — the codemods only rewrite classes.

All 43 tiptap packages are pinned by name in resolutions. Bumping only our
ten direct deps left frappe-ui's transitive @tiptap/extension-* at 3.27.1,
each declaring an exact @tiptap/core peer, which produced 19 nested copies of
core; yarn v1 ignores a "@tiptap/**" glob resolution.

tailwind.config.js now spreads the preset's own content export. The
hand-written globs it replaces covered src/components and src/molecules
only, silently dropping every class the editor and list molecules emit.

Testing

  • Frontend unit tests 66/66 (node --test over src/**/*.test.js), up from 47
    — the callout markdown suite gains block-children cases and a fidelity check.
    A fixed point alone proves nothing: content that degrades to plain text
    round-trips just as stably.
  • yarn build clean. Verified the editor and list stylesheets still ship after
    dropping the explicit CSS imports.
  • New backend tests cover branch_exists and the space-list counts.
  • The callout e2e spec now creates a throwaway space per test rather than
    authoring into whichever space the site lists first — that tree grew with
    every run and was never cleaned up, which is what made it flake locally.
  • Local Playwright is not a clean signal on this machine — the dev site
    holds 1847 spaces and 11k documents of fixture data and the web server dies
    partway through long runs. CI is the verdict.

Specs: specs/frappe_ui_beta45_upgrade.md, specs/callout_container_node.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pba2JytJJxKYqHw239BZY5

NagariaHussain and others added 30 commits August 11, 2026 14:46
Inventory of the 696-commit delta, restricted to what touches wiki:
four loud breaks, thirteen silent ones, two non-idempotent codemods,
and a phased order that puts the useFileUpload privacy audit first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clears every break in the delta that fails the build.

- tiptap moves to 3.29.2 as a set. @tiptap/markdown declares exact peers
  on @tiptap/core and @tiptap/pm at its own version, so a partial bump
  leaves two cores in the tree. yarn v1 ignores a "@tiptap/**" glob
  resolution, so all 43 packages are pinned explicitly.
- frappe-ui/editor-style.css and frappe-ui/list-style.css are gone. The
  editor and list barrels self-import their CSS and are marked
  side-effectful, so the stylesheets ship with the subpath imports. The
  built output still carries 119 ProseMirror and 36 list-slot rules.
- pageMetaPlugin is removed. Nothing declares the pageMeta() option;
  Spaces.vue already uses usePageMeta.
- Alert is redesigned and stateless. It was registered globally with no
  call sites, so the registration goes rather than the migration.
- Autocomplete is removed. AssignDialog used it with `multiple`, so it
  becomes MultiSelect, whose model is a value array rather than option
  objects.
- tailwind.config.js spreads the preset's own `content` export. The
  hand-written globs it replaces covered src/components and src/molecules
  only, dropping every class the editor and list molecules emit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The named radius aliases are removed in frappe-ui 1.0.0 (ADR-0006). The
preset replaces Tailwind's borderRadius scale, so an unmigrated
rounded-md emits no CSS at all — square corners, no build error.

Applied with `tokens-v2 --radius-only` across the editor SPA and the
public reader's Jinja templates: 113 renames over 29 files. --radius-only
rather than the full codemod because the color and typography passes
already ran during the beta.25 upgrade and neither is idempotent.

The three var(--radius-sm|lg) reads are hand-migrated — the codemod only
rewrites rounded-* classes, and the alias CSS variables go away with the
aliases. Pixel values are identical throughout; this changes vocabulary,
not rendering.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The updated espresso v2 export shifts every chromatic ink scale down one
level — the new ink-red-1 is the old ink-red-2 — and the scales now end
at -9. ink-gray keeps its own 9-step scale and does not shift. Nothing
warns: every ink-<family>-N site renders one shade off after the token
update, so this lands with the upgrade rather than after it.

Applied with `tokens-v2 --ink-shift` over frontend/src and wiki/templates
(33 renames, 11 files). The mode has no sentinel it can read back from
file content, so it writes a .tokens-v2-ink-shift marker in each target
and refuses to run again; the markers are committed so a fresh clone
keeps the guard.

The six var(--ink-<family>-N) reads in the reader's hand-written CSS are
migrated by hand — they sit beside generated files the codemod would
rewrite for nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
None of these fail the build. Each one renders wrong instead.

- Tabs is a composed family now and models the trigger value, not an
  index, so the index round-trip through the tab query goes away.
  Composed rather than the `:tabs` shorthand because v1 ships no layout
  defaults: the panel has to be a constrained flex column for
  ContributionsPanel to scroll, and generated panels take no classes.
- Dropdown ignores `placement` and falls back to align="start", so both
  right-aligned menus quietly moved left.
- PageHeaderMobile's #left/#right are #prefix/#suffix. Vue drops content
  passed to an unknown slot, so the tree toggle and the two menus just
  stopped rendering.
- Combobox's template ref exposes clear(), not reset().

Audited and unchanged: all three useFileUpload calls already pass
`private: false`, so the default flip to private cannot 403 an editor
image or a space logo; Select's trigger slot is unused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The change-card locator matched on `rounded-lg`, which the radius codemod
renamed to `rounded-6` in the source. The class is gone from the markup,
so the locator resolved to nothing and the Reordered label assertion
timed out.

The only e2e locator in the suite that matched on a token class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Records the two corrections the work forced on the plan — the radius
codemod needs --radius-only because the color and typography passes
already ran and are not idempotent, and the tiptap resolutions have to
name all 43 packages because yarn v1 ignores a glob — plus the four
breaks that turned out to need no change, and the e2e baseline that
separates the upgrade's one real test break from local flake.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
frappe-ui 1.0.0-beta.41 switched sync-tokens to oklch, so colors.json
holds oklch() where it used to hold hex. The OG card template declares
those six values inline, and the drift test compares the two directly:

    AssertionError: '#0f0f0f' != 'oklch(0.168 0 0)'

The card renders through headless Chromium, which reads oklch, so the
template carries the new notation rather than a hex approximation of it.
The test's scraper accepts either notation, so it keeps comparing what
colors.json actually holds instead of assuming one form.

TEMPLATE_VERSION is part of the cache fingerprint, so bumping it drops
every cached card.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A callout's markdown never reached a fixed point under tiptap 3.29.2:
every parse/serialize pass appended two more newlines, so repeated saves
inflated the stored content without bound.

    :::note[Test]\nhello\n:::\n\n\n\n
    :::note[Test]\nhello\n:::\n\n\n\n\n\n
    :::note[Test]\nhello\n:::\n\n\n\n\n\n\n\n

renderMarkdown appended its own `\n\n` after the closing fence. The
serializer already separates blocks and the doc's trailing empty
paragraph serialises to another blank line, which put four newlines after
the fence. Four is one past where PreserveBlankLines turns marked's
`space` token into a real empty paragraph, and that paragraph then
serialised to two more newlines on the next pass. Paragraphs, headings
and lists were stable throughout because they leave the separator to the
serializer; the callout is now the same.

The markdown hooks move to callout-markdown.js so they can be tested:
callout-block.js imports a .vue node view at the top level, which
`node --test` cannot load. Verified by reverting the one-line change with
the tests in place — six round-trip cases and both direct assertions fail
without it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FeatherIcon and its bare-name back-compat are removed in frappe-ui 1.0.0
(ADR-0008). A string that does not start with `lucide-` now resolves to
nothing — renderIcon returns null and dev logs one warning per component
and prop — so every `icon="settings"` and `icon: 'trash-2'` in the app
silently stopped drawing: dropdown rows, tree actions, review actions,
the space chrome bar.

All 41 sites take the `lucide-` prefix. Every name survives the move
except `github`, which lucide dropped along with the rest of its brand
icons; the two GitHub affordances use `lucide-git-branch`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SidebarHeader is a fixed 48px region that owns its own gutter, so it is
meant to go straight into Sidebar. Our wrapping `p-2` div added a second
one, pushing the logo and title in past every row below them.

Padding moves to the scroll region and the footer, which is what v1's
composition contract asks for now that Sidebar no longer applies any of
its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
useColorScheme owns everything the local composable was doing by hand:
the `data-theme` attribute, persistence, following the OS, and muting
transitions across a swap so the page doesn't flash. Its version also
cancels a pending unmute, so back-to-back swaps can't uncover a repaint —
which the two-rAF dance here could. The `.no-transition` rule goes too;
frappe-ui/style.css ships it.

What stays local, and why:

- The toggle flips the *painted* scheme rather than delegating to
  toggleColorScheme, which branches on the preference: starting from
  `system` on a dark OS it picks `dark`, and the first click looks dead.
- `resolvedTheme` tracks the `data-theme` attribute through a
  MutationObserver. DiffViewer and MermaidBlockView need the painted
  scheme, and it isn't derivable from the preference — `system` resolves
  against the OS, and an OS flip repaints without changing the
  preference, so there is nothing reactive to watch.

The storage key moves from `wiki-theme` to frappe-ui's `theme`. A saved
value under the old key is copied over once, and the public reader —
which keeps its own Alpine implementation, having no frappe-ui to import
— reads the new key with the old one as a fallback and writes the new
one, so a toggle on either surface still reaches the other.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
All three tab panels rendered at once, splitting the height three ways
and clipping the list after about three rows.

reka keeps an inactive TabsContent's wrapper in the DOM and drops only
its slot content, marking the wrapper with `hidden`. Tailwind's preflight
turns that into `display: none` via `[hidden]`, which is a single
attribute selector — exactly as specific as a `.flex` utility, and
utilities are emitted after preflight. So the `flex` this call site put
on TabPanel won the cascade, and every panel stayed a visible flex child
claiming `flex-1`.

Moving `display` behind `data-[state=active]:` leaves `hidden` to win on
the inactive ones. `min-h-0` and `flex-1` are inert while hidden, so they
can stay unconditional.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The underline variant's indicator is a 1px rail line. It measured and
positioned correctly, but against the dark theme it reads as part of the
track border rather than as a selection, so the active tab looked
unmarked.

TabList has full variant parity with TabButtons, so the button-style
track is a prop rather than a different component — and the composed
family keeps owning the panels, which TabButtons does not do.

Page padding moves to a wrapper: the pill track hugs its content, so
padding on TabList itself would sit inside the pill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`icon: node.is_published ? 'eye-off' : 'eye'` kept bare Feather names, so
the publish toggle in the tree's three-dot menu drew no icon. The upgrade
sweep that prefixed the other 41 call sites matched `icon: '...'` and
`icon="..."` only — a ternary's branches were invisible to it, and it ran
over .vue files alone.

Rather than grep harder next time, this adds a test that walks every
source file, isolates each icon key or prop's own expression, and fails
on any string literal in it that is not a `lucide-` class. It reads
ternaries, template props and bindings, and .js as well as .vue.

The break is silent by design — v1 renders null for an unsupported icon
string and only warns in dev — so a build and a passing e2e run both stay
green while the icon is missing. Verified by restoring the bare names
with the test in place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two breaking changes land in the wiki:

- Badge dropped the `orange` theme. Every `orange` badge — unpublished
  pages, dirty settings panels, reordered nodes, "In Review" change
  requests — moves to `amber`, the nearest surviving warm theme. An
  unrecognised theme renders no color classes at all, so these badges
  would otherwise have gone unstyled.
- SettingsDialog renamed its open model from `modelValue` to `open`.
  Both wrappers now bind `v-model:open`.

Dialog's `yellow` theme also became `amber`, and the v1 chart family,
CommandPalette and `useShortcut` left the root export for
`frappe-ui/experimental` — none of which this app uses.

Verified in the browser: both settings dialogs open, close on Escape
and reopen; badges render in light and dark.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The light-mode content pane floated as a rounded, shadowed card over the
sidebar surface while dark mode was already flat. The app window rounds
the outer corners itself, so the inner radius only read as noise — both
themes now share one flush treatment with a hairline divider.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both tables already used the frappe-ui/list family but diverged from the
documented idioms in three ways.

Skeletons and rows now share one List, so the track list is declared once
instead of being mirrored in a hand-built grid that could drift from it.

`list-row-px-3` sets the content inset on the List, which flows to both
the header and the rows; without it the header sat flush while the
interactive rows carried the family's default 0.75rem.

Mobile collapses each table to a feed through a `--list-columns` override
rather than scrolling a min-width table sideways. The header needs
`!hidden` there: the family sets `display: grid` at attribute specificity
to survive preflight resets, which a plain `hidden` utility ties with and
loses to on order.

Also drops the `selectable` / `showTooltip` / `resizeColumn` options left
over from the config-driven ListView — nothing reads them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The space list was a four-column table (name, status, route, a View
button) that needed a responsive override to survive a phone. The list
family's default feed template carries the same information in less
space and reflows on its own, so the override is gone.

Each row is now a square Avatar of the space logo, the space name over
its route, and the page count above the published badge.

Page counts come from a new grouped query rather than a field on the
list: Wiki Space stores no count, and a call per row would scale with
the page size. Groups are folders and external links point elsewhere, so
neither counts as a page; unpublished pages do, since this is the
editor's list and a draft is still a page to maintain.

The View button is dropped — the row already opens the space, and the
public reader is one click away from there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…list

The list ran the full width of the content pane, which left every
trailing cell a screen away from the title it belonged to. It now reads
as a centered column, with search, the filter, and the tally sharing one
row above it.

Search comes first, then a TabButtons segmented control for All /
Published / Unpublished, then the number of spaces on the far side. The
row wraps on mobile so search keeps a line to itself.

Status moves out of the trailing cell into a column of its own, so the
badges line up down the list instead of stacking under the page counts.
The page-count column is the one dropped on mobile.

get_space_count backs the tally. It takes the same search and filter the
list does, because frappe.client.get_count has no or-filters and the
list searches name *or* route -- counting through it would have tallied
something other than what is on screen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The list scrolled in a plain overflow-auto div inside the narrow column,
so the scrollbar ran down the middle of the pane beside the rows.

frappe-ui's ScrollArea now owns the scroll region and spans the pane, so
its overlay scrollbar rides the content edge. The narrow width moves onto
the toolbar and the row wrapper, which repeat it so the two still line
up; the page box drops its padding, since the scroll region has to reach
the edge and the horizontal inset belongs to the content inside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Callouts are atom nodes whose body is a string attribute, so rich text
needs a nested Editor and a hand-built B/I/Link toolbar. TipTap's
container pattern (content expression + NodeViewContent) puts the body
in the main document instead, which brings every mark and block node the
editor already has. Restyle to match frappe-ui's Alert at the same time:
one neutral surface, color only in the icon.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The branch picker only offered what GitHub listed, so a branch outside the
first page (or one the picker never loaded) could not be chosen at all.

Autocomplete gains an `allow-custom` mode: typed text that matches no option
is committed on Enter, blur, or outside-click, so clicking straight through to
a dialog action still keeps the value. Esc still discards.

`branch_exists` asks GitHub for the single branch rather than scanning
`repo_branches`, which caps at 100, and the create form calls it before
inserting so a typo surfaces in the dialog instead of failing the first sync.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The toolbar sat flush to the narrow column while the rows carried the
List's own content inset, so the tally hung a row-inset past the status
badges and search started a row-inset left of the avatars. Both now share
one wrapper shape and the toolbar mirrors the row inset, so the two edges
line up.

Two columns join them. Last updated is the newest page edit in the space,
not the space document's own `modified` -- that one moves when someone
renames the space or flips a setting, which says nothing about whether
the content is current, so a space with no pages shows nothing rather
than a fresh-looking date. Open change requests counts anything not
merged, rejected or archived, the same reading as an open pull request,
and takes the pull-request glyph.

Both are an icon and a number rather than a phrase: at this column width
the glyph carries the label and the title attribute spells it out. The
three measure columns drop on mobile, where the status badge is the one
thing worth the width.

get_space_page_counts becomes get_space_stats and returns all three in
one call, so the row still costs a single round trip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The body was a markdown string in an attribute, so the node view ran a
second Editor and a hand-built B/I/Link toolbar to make three marks
editable. It is now real document content (content: 'block+' plus
NodeViewContent), which hands the callout every mark and block node the
main editor already has: lists, headings, code blocks, images, Cmd+K
links, the bubble menu and undo history.

The stored format is unchanged, so no migration: the fence body is
tokenized with the lexer and parsed into child nodes, and serialized back
through renderChildren.

The markdown unit tests grow the block-children cases and a fidelity
check — a fixed point alone proves nothing, since content that degrades
to plain text round-trips just as stably. Registering the plain
CodeBlock in the harness is what makes the fenced-block case meaningful:
wikiStarterKit disables it because frappe-ui's version can't load under
node --test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The row had grown to six columns of icon-and-number pairs, which is not
what the list family's feed recipe does. It is back to the recipe's
shape: leading avatar, the two-line title block, and a right-aligned
trailing stack of muted lines -- with the status badge lifted out into a
column of its own between them.

The trailing stack carries the page count over the last edit. Both read
as prose again: "No pages" rather than "0 pages", and "Updated 9 minutes
ago" rather than a bare "9 minutes ago", which read as an unlabelled
timestamp for the whole row.

The title column is capped rather than flexible, with the slack going to
the trailing stack instead. On a 1fr title column a short space name left
the status badge floating a third of the row away from the text it
describes.

Open change requests come back out. They were an extra grouped query for
something the Change Requests page already presents properly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The title moves out of the dialog into an input in the header row, with
the type's default title as its placeholder. Enter moves into the body.

A callout is isolating, so ProseMirror's own exits don't apply: at the end
of the document there is nothing after the node to move into. Mod-Enter
and ArrowDown-at-the-end now open a paragraph after it, and Backspace at
the start of an empty callout deletes the node instead of doing nothing.

The e2e spec now creates a throwaway space per test rather than authoring
into whichever space the site lists first. That space's page tree grows
with every run and was never cleaned up, which is what made the suite
flake locally once it held enough pages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
frappe-ui ships raw source and reaches its own files through the
`#molecules/*` imports map. esbuild resolves a mapped path with Node
semantics and never tries an extension, so pre-bundling `frappe-ui/editor`
and `frappe-ui/list` failed on every internal import — 57 "Could not
resolve" errors and a dev server that served nothing. Vite's own resolver
handles the same paths, so exclude the entries and let it serve them.

Drop `feather-icons` and `interactjs` from optimizeDeps.include while
here: neither package is installed or imported, and each logged a
"Failed to resolve dependency" line on every dev start.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One neutral surface (surface-gray-1, rounded-6, p-3, no border) with the
type's colour carried only by the icon, which is now the same solid Figma
status glyph Alert resolves for that theme. Those four SFCs are not
exported from frappe-ui/icons, so the paths are inlined — the
server-rendered reader needs the same ones in markdown.py anyway.

Body typography follows Alert's description: full width under the header
rather than indented beside it, since the header is its own row now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
NagariaHussain and others added 4 commits August 27, 2026 13:07
The server-rendered callout gets the same treatment as the editor: a
header row (icon + title) over a full-width body, one neutral surface,
and the Alert status glyph in the type's colour. The `.callout-body`
wrapper and the two-column grid are gone — the body is no longer
indented beside the title.

Public icons were also a shade off: they used the -2 inks where the SPA
used -5.

Print resolves the tokens to hex and floats the icon, since that pipeline
has no CSS variables and QtWebKit parses neither oklch() nor flexbox.

Drops the callout rules from wiki-rendered.css, whose only consumer — the
standalone CR preview page — was removed in afb6808. The rest of that
file is dead for the same reason but is left alone here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The default title was an input placeholder inked like real text, so it
looked editable but wasn't: putting a cursor in it and pressing Backspace
did nothing. It is a value now — seeded on insert, and filled in on parse
for a fence written without [Title].

The serializer drops the brackets again while the title still equals the
type's default, so a wiki full of :::note isn't rewritten to
:::note[Note] the first time each page is saved. Clearing the title
restores the default on blur, since the rendered page always prints one,
and changing type only carries the title along if the author never
touched it.

The three-dot action is "Remove" rather than "Delete".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Alert's description is full-bleed, but every Alert story renders the
component inside max-w-sm — a 384px status box with a one-sentence
description. A callout is the document's width and holds paragraphs and
lists, and at that size the title (indented behind the icon) and the body
(at the container edge) give the block two left edges, so the header
reads as detached from what it labels.

The body is now indented to the title's left edge — the icon plus the
header gap — in the editor, on the public page and in print.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NagariaHussain NagariaHussain changed the title feat/frappe ui beta55 chore(deps): upgrade frappe-ui to 1.0.0-beta.55 Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant