Skip to content

Releases

yugen-ui 0.16.0

Choose a tag to compare

@github-actions github-actions released this 10 Nov 08:32
a71a92f

Minor Changes

  • Charts: moving the pointer over LineChart, AreaChart and BarChart no longer recomputes the chart (#352). Scales, paths, the screen reader label of every point and the layers that do not change on hover are kept until the data, the props or the width change, and the points share one set of event handlers, so a hover step only redraws the crosshair, the tooltip and, for bars, the bars whose dimming changes. A hover step goes from 9.7 to 1.1 ms at 500 points and from 39 to 1.1 ms at 2,000 (three series, jsdom), and a keyboard step from 43 to 9.6 ms at 2,000. Colors shared by a series (line markers, bars) and the gridlines are set once on the series group instead of on every mark: a 4 × 200 LineChart with markers has 16 inline styles instead of 1,014 (−30% markup), a 60 × 4 BarChart 13 instead of 490 (−14%). The drawn pixels, keyboard navigation and screen reader output are unchanged; points now carry a data-i attribute. { BarChart, LineChart } grows from 30.2 to 31.1 kB gzip. New useElementSize({ enabled }): with false the hook measures nothing and adds no ResizeObserver. Sparkline passes enabled: false when width is a number, so 200 fixed-width Sparklines mount in one render instead of three, with no observers.
  • New yugenHtmlAttributes() and yugenThemeScript() for server-rendered and prerendered apps, so the first paint uses the right theme (#348). <html {...yugenHtmlAttributes({ theme, brand, dir })}> writes the same attributes as <YugenProvider applyToDocument> into the first HTML. yugenThemeScript({ storageKey }) returns a small inline script for <head> that sets data-theme before the first paint, from the saved choice (a theme name, or JSON with theme, brand and dir) or else from prefers-contrast and prefers-color-scheme. Both are plain functions that work in a Next.js Server Component. YugenProvider applyToDocument now writes the attributes in a layout effect, before the browser paints, instead of after it.
  • New useYugenTheme() ({ theme, brand, dir }) and useYugenLocale() (the Intl locale): unlike useYugen(), a component that reads one of them does not re-render when the other changes. YugenProvider keeps the theme in its own context, so a theme switch no longer re-renders every control that reads defaults or messages: with 1,800 controls and stable children (a Next.js Providers component, a wrapper that passes children), it goes from about 66 ms and 1,500 re-renders to 1.4 ms and none. messages written inline (messages={{ dialog: { close: "Close" } }}, { ...messagesVi, … }) is now compared by value like defaults, so a parent re-render with the same strings no longer re-renders those controls (66 → 0.1 ms). Charts, CodeBlock, the date and time pickers and the other components that need only the theme or the locale use the new hooks. useYugen() returns the same fields as before (#347).
  • New subpath imports (#344): every component folder is also a path of the package, as in import { Button } from "yugen-ui/Button", yugen-ui/Chart or yugen-ui/DatePicker, plus yugen-ui/hooks, yugen-ui/AppShell/Sidebar, yugen-ui/messages-en and yugen-ui/messages-vi. A subpath loads only that component and what it uses, which matters where nothing tree-shakes the package: tests, server rendering in Node and dev servers. A cold import { Button } in Node loads 14 modules in about 60 ms from yugen-ui/Button, against 498 modules in about 1.6 s from yugen-ui. Production bundles keep the same size, and the root and the subpaths load the same files, so both can be used in one app. yugen-ui/_internal/* stays private. The Quick start page lists the paths and shows Next.js optimizePackageImports for apps that keep importing from the root.

Patch Changes

  • Calendar no longer bundles the Vietnamese date-fns locale: it checks the locale code instead of importing vi. English apps save about 2 kB gzip on every date component: { Calendar } goes from 32.4 to 30.4 kB and { DatePicker } from 58.8 to 56.8 kB (Rolldown, as in Vite 8). Vietnamese apps still get the locale through calendarMessagesVi / messagesVi, and the short weekday names (CN, T2…) work as before (#349).
  • Leaner CSS floor (#353). The library's 19 keyframes now live inside @theme, so Tailwind only outputs the ones an animate-* utility (or an animation declaration) in your app uses: with theme-core.css, a Button-only app goes from 20 keyframes to 1 (9.17 → 8.86 kB gzip in a Vite build) and the floor with no components from 7.15 to 6.85 kB. Utility and keyframe names are unchanged, including animate-shimmer and animate-indeterminate; WavyUnderline uses the new animate-wave-flow. As with Tailwind's own keyframes, they are written at the end of the output: an app that defines its own @keyframes with one of these names (fade-in, sweep…) should declare it inside @theme for it to win. tokens.css no longer carries the @theme block and chart keyframes of charts.css, so it is plain CSS with custom properties only (8.22 → 8.02 kB gzip). styles.css keeps the keyframes its components use and drops the unused shimmer and indeterminate. theme.css is now @import "./theme-core.css" plus its @source line instead of a second copy of the theme (64 kB less in the package).
  • Components with class variants (Button, Input, Badge, Card, Tag, Avatar, Label, Link, Select, Textarea, MessageBar, ButtonGroup, Image, SwatchPicker and the ToggleButton checked layer) merge their classes once per combination of variant props instead of on every render (#355). Server-rendering 1,000 Buttons takes half the time (about a third less with a className), re-rendering them in the browser 44–51% less (30–32% with a className), and the docs' server-rendered pages 2–11% less. The exported buttonVariants, buttonGroupVariants, linkVariants and imageVariants take the same arguments and return the merged string: the classes the component renders, which is what cn(buttonVariants(…)) returned before. cn keeps 2,000 merged strings instead of 500, so a large page no longer evicts its own entries. Copied source (yugen add, the shadcn registry) gains lib/cvx.ts next to lib/cn.ts.
  • Deprecate YugenProvider's withToaster prop with a development warning and point templates and documentation to an explicit <Toaster /> child. The prop remains available until 1.0.0.
  • Parts that only one option needs now load on demand (#350). Nav no longer imports Tooltip: the AppShell Sidebar passes the icon-rail tooltip to it, so a Nav outside AppShell goes from 29.9 to 12.0 kB gzip (Rolldown, as in Vite 8). Breadcrumb loads the menu of its "…" button only when maxDisplayedItems collapses items (initial chunk 40.2 → 13.5 kB), and StreamingMarkdown loads the citation card only when the text has citations (49.3 → 27.3 kB). Until the part arrives, which starts right after the first client render, the button or chip renders with the same size, classes and ARIA; a click or key press in that window opens the menu or card once it arrives, and focus moves to the real button. Server rendering and hydration always render that placeholder, so both sides produce the same HTML. A lean dashboard (YugenProvider, Nav, Breadcrumb, Card, Button, Badge, Field, Input) goes from 51.2 to 32.2 kB and an AI chat page (YugenProvider, StreamingMarkdown, PromptInput, MessageScroller, Reasoning) from 63.8 to 54.1 kB; apps that already use Menu, Tooltip or Popover elsewhere see little change. Tests that open the Breadcrumb menu or a citation card right after rendering need to wait for it (findByRole). With esbuild code splitting (splitting: true), an import from the package root puts these parts into the first chunk even when the app does not use them, because esbuild assigns whole files to chunks; import from subpaths such as yugen-ui/Breadcrumb there.
  • Combobox and TagPicker no longer use cmdk: a small built-in listbox engine handles the highlighted option, aria-activedescendant and the keyboard (#351). { Combobox } goes from 42.83 to 38.92 kB gzip and { TagPicker } from 50.56 to 41.01 kB; Command keeps cmdk. With 1,000 options an arrow key now takes one render that updates only the two options whose highlight changed (Chromium: about 40 → 2.6 ms per key, typing 30 → 7 ms per key, opening 300 → 210 ms). Keyboard and the look are unchanged; options keep role="option", data-selected and data-disabled, but no longer carry cmdk-* attributes, so tests that query [cmdk-item] inside a Combobox or TagPicker should query role="option" instead. The listbox is now named by the field label (aria-labelledby, which Field sets) instead of the fixed English "Suggestions"; without one it reuses the input's aria-label, and with neither it uses the new listLabel message (messages.combobox.listLabel, messages.tagPicker.listLabel: "Suggestions" / "Gợi ý"). TagPicker loads Sortable only with reorderable: the server and the first render show plain tags of the same size, and dragging and Alt + arrow keys work as soon as it has loaded (tests should wait for it, for example for [data-sortable-item]). A tag that has focus when Sortable arrives keeps it.
  • Fix types under TypeScript module: "node16" / "nodenext" (#343): the root declarations pointed at the Chart, AIKit and hooks modules without a .js ending, so 72 exports (BarChart, LineChart, StreamingMarkdown, PromptInput, useDisclosure, useHotkeys…) failed with "has no exported member". MenubarMenu no longer names @radix-ui/react-context in its type, a package yugen-ui does not depend on. CI now type-checks every export from a nodenext project and runs Are the Types Wrong on the package.
  • Fix three details of the published package (#382). Deprecation warnings are in English and link to https://trandat1114.github.io/Yugen-UI/concepts/versioning instead of the old #/ URL. The AppShell cookie gets `sec...
Read more

@yugen-ui/cli 0.8.0

Choose a tag to compare

@github-actions github-actions released this 10 Nov 08:38
a71a92f

@yugen-ui/cli 0.8.0 and create-yugen-ui 0.8.0.

  • yugen css --watch keeps the lean CSS file current while source imports change. The bundled Next.js template runs it beside
    next dev; Vite templates include @yugen-ui/cli/vite and yugenCss(). init wires the Vite plugin into an existing
    Tailwind CSS v4 project. --watch cannot be combined with --check.
  • init, doctor and theme now print an explicit <Toaster /> inside the root <YugenProvider> instead of the deprecated
    withToaster prop.
  • yugen css: writes yugen-ui.css with @import "yugen-ui/theme-core.css"; and one
    @import "yugen-ui/sources/<Folder>.css"; per component folder your code imports, instead of theme.css with every
    component. On the templates the gzipped CSS goes from about 26 kB to 12–20 kB (−24% to −54%). Imports are read with
    a small lexer, so examples inside strings, comments or JSX text don't count; import * as, export * and
    import() of yugen-ui fall back to theme.css. --check exits with 1 when the file is out of date; --src
    limits the folders it reads; --precompile compiles plain CSS for apps without Tailwind (26.8 kB → 12.8–21.1 kB)
    with the project's own tailwindcss, @tailwindcss/node and @tailwindcss/oxide (#169).
  • init (package mode, Tailwind CSS v4) writes yugen-ui.css and imports it instead of yugen-ui/theme.css. A CSS
    file that already imports theme.css is left as it is.
  • add in package mode adds the component to yugen-ui.css when the app has one.
  • doctor accepts yugen-ui/theme-core.css (it reported "theme not imported"), warns when yugen-ui.css is out of
    date or not imported, and names the components imported without their sources/<Folder>.css.
  • No runtime dependencies: own prompts on node:readline and colors with node:util styleText replace
    @clack/prompts and picocolors (#381).
  • Bundled templates ship package.json as _package.json; create renames it back. Scanners no longer read the
    templates' manifests as dependencies of the CLI (#381).
  • create --ref no longer reads GITHUB_TOKEN / GH_TOKEN (#381).
  • add / update refuse registry file paths that leave the target folder and dependency specs that are not npm
    package specs; on Windows the package manager that launched the CLI runs without a shell (#381).
  • LICENSE file in @yugen-ui/cli and create-yugen-ui; homepage points to the path URL of the CLI page.

Full notes: packages/cli/CHANGELOG.md · News

yugen-ui 0.15.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 00:35
94c96c9

Minor Changes

  • New prop names from the pre-1.0 API review (#157), so the same idea has the same name everywhere: Carousel gap="extra-small" | "small" | "medium" | "large" | "extra-large" (default "small"), Tree onSelectionChange, DatePicker and DateRangePicker onValueChange (receives null when cleared, like value), List appearance, RatingDisplay showValue (default true), toast option dismissible (default true), CarouselNavContainer previousLabel and Autocomplete noResultsText. Sheet and NotificationCenter breakpoint take the same tokens as AppShell ("lg" … "5xl", default "3xl" = 48rem = 768px). Also new: TimePicker onValueChange(Date | null) next to onTimeChange, Carousel activeIndex / defaultActiveIndex, and Stepper defaultActiveStep.

    The old names keep working until 1.0 and print a one-time warning in development: Carousel gap="XS" | "S" | "M" | "L" | "XL" and circular, Tree onSelectedChange, DatePicker onSelectDate, DateRangePicker onSelectRange, List variant, RatingDisplay hideValue, toast hideDismiss, CarouselNavContainer prevLabel, Autocomplete emptyMessage, a px number for Sheet / NotificationCenter breakpoint, and formatDateVi. The unsuffixed …Messages constants (for example carouselMessages) are marked @deprecated in favour of …MessagesVi / …MessagesEn.

  • More names from the pre-1.0 API review (#157), the rows planned for 0.16, shipped early: CarouselNavContainer showAutoplayToggle (Carousel's own autoplay is the autoplay state), TimelineItem intent="error" (like MessageBar, Toast and Field), Stat and StatTile size="extra-large", Divider orientation="horizontal" | "vertical" and TeachingPopoverFooter orientation.

    Deprecated (they keep working until 1.0 and print a one-time warning in development): CarouselNavContainer autoplay, TimelineItem intent="danger", Stat size="hero", Divider vertical, TeachingPopoverFooter layout, and three exports that leave the package in 1.0: highlightRanges (internal helper of HighlightMatch), getOverflowGroups (use useIsOverflowGroupVisible(groupId)) and the top-level dispatchToast (use toast() or useToast().dispatchToast, which do not warn).

  • Breaking: yugen-ui no longer depends on @fluentui/react-icons (about 180 MB installed, plus the Griffel CSS-in-JS runtime). The 159 icons used inside components now ship with the library as small inline SVG components generated from Fluent System Icons, with the same paths, sizes and accessibility attributes, so components look the same. Apps that import icons from @fluentui/react-icons themselves and relied on it being installed with yugen-ui must add it to their own dependencies (npm i @fluentui/react-icons); the templates already do. Icon slots size any SVG with CSS, so other icon sets such as lucide-react work in them too (#320).

  • New ColorPicker: a saturation / brightness area, hue and optional opacity (alpha) sliders, HEX / RGB / HSL inputs, a screen color picker where the browser supports the EyeDropper API, and preset colors through SwatchPicker (swatches). The value is hex; onValueChange also gets rgb / hsl / hsv. parseColor is exported, and built-in strings live in messages.colorPicker (#173).

  • New FormattedInput with format="phone" | "card" | "currency": formats as you type and keeps the caret in place, including edits in the middle and Backspace over a separator. value / onValueChange use the raw value (digits, or a decimal like "1234.5"); with name, forms submit the raw value. Phone masks follow the locale region (or mask), card numbers group by card type, and currency uses Intl with the provider locale and currency. Also exported: applyMask, getPhoneMask, getCardMask (#173).

  • Yugen Labs: glassNavigationDefaults, a set of default props for YugenProvider that gives every navigation component with glass material="glass" in one place (#230): <YugenProvider defaults={glassNavigationDefaults}>, or { ...glassNavigationDefaults, Button: { … } } together with other defaults. It covers Toolbar, TabsList, Nav, MenuPopover, MenuSubPopover, PopoverSurface, TooltipContent, DialogSurface, DrawerSurface and SheetContent; a material prop on an instance still wins. MenuSubPopover exports its props type, MenuSubPopoverProps.

  • New MonthPicker, YearPicker and DateTimePicker in the DatePicker family: the same field, popover, value / defaultValue / onValueChange (Date | null), minDate / maxDate, clearable, formatDate and locale handling as DatePicker. MonthPicker and YearPicker show a 12-cell grid with arrow keys, Home / End and PageUp / PageDown; DateTimePicker pairs the Calendar with a TimePicker (timeIncrement, hourCycle). Built-in strings live in messages.monthPicker, messages.yearPicker and messages.dateTimePicker (#173).

  • New NavigationMenu for website headers (#168), built on Radix Navigation Menu (new dependency @radix-ui/react-navigation-menu): NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink (active sets aria-current="page"; icon and description inside a panel; asChild for router links) and NavigationMenuIndicator. Hover intent with a short delay, activationMode="manual" to open on click only, keyboard support per the WAI-ARIA disclosure navigation pattern, one floating viewport that resizes to the open panel, RTL. The <nav> label comes from messages.navigationMenu.

  • New PasswordInput: an Input with a show / hide button (aria-pressed, keeps focus in the field), a Caps Lock note read through a live region, and an optional strength meter (strength, or your own scoring function; getPasswordStrength is exported). Built-in strings live in messages.passwordInput (#173).

  • Prose reads its fonts and rhythm from CSS variables: --prose-font-body, --prose-font-heading, --prose-font-mono, --prose-size, --prose-leading and --prose-flow (space between blocks). With none of them set it looks exactly as before. New presets in the theme: yugen-prose-docs, yugen-prose-article, yugen-prose-chat and yugen-prose-compact. The docs have a Typeset page that builds your own preset and copies the CSS (#244).

  • YugenProvider takes defaults and density (#171). defaults={{ Button: { shape: "circular" }, Input: { appearance: "filled-darker" } }} sets props for every instance of a component in that part of the UI, typed per component; a prop on the instance still wins and nested providers merge per component. density="compact" gives controls (buttons, fields, pickers, tabs, toolbars, tables, Tree, Nav…) size small by default and scales spacing by 0.9375; "comfortable" scales spacing by 1.125. Spacing comes from a data-density attribute in theme.css (--spacing and the spacing tokens, the same factors as the Theme Designer), so prerendered HTML is right before hydration. useYugen() also returns density. Each component reads its defaults with one context read.

  • Breaking: React 19 or later is required (peerDependencies react / react-dom >=19). React 18.3 was supported through 0.14; it gets no fixes upstream since 2024-04, and CI no longer tests it. Apps on React 18 can stay on yugen-ui@0.14 until they upgrade (#62).

  • Components are plain function components that take ref as a prop (React 19) instead of forwardRef wrappers. Passing a ref works as before, and React.ComponentRef<typeof Button> and React.ComponentProps<typeof Button> still give the element type and the props (with ref). In the type declarations each component is now a function such as Button(props: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) rather than a React.ForwardRefExoticComponent, so code that spelled out ForwardRefExoticComponent for a Yugen component should use typeof Button or React.ComponentType<…>. DataGrid and DataGridColumnPicker are declared as generic functions directly. Components that keep their own ref next to yours (Carousel, Sheet, Toolbar, FileUpload and others) now call the cleanup function that a callback ref returns when the element is removed (#62).

  • YugenProvider scrollLock chooses whether the page scrollbar stays while Menu, ContextMenu or Dropdown is open (#243). These surfaces lock page scrolling through Radix (react-remove-scroll), which hides the scrollbar and adds a body margin in its place. "hide-scrollbar" keeps that behavior and stays the default in 0.x; with "keep-scrollbar" the scrollbar stays and nothing shifts, while wheel and touch scrolling outside the surface are still blocked. With applyToDocument the provider writes data-yugen-scroll-lock to <html>; apps without the provider can set the attribute themselves (the CSS is in theme.css). Menu and ContextMenu document modal={false} for a menu that doesn't lock scrolling at all. 1.0 will switch the default to "keep-scrollbar".

  • New StatusPage and ErrorBoundary (#238). StatusPage is a page for HTTP errors and app states: status (400, 401, 403, 404, 408, 410, 429, 500, 502, 503, 504, "offline", "update") picks the built-in title, description and code from messages.statusPage; primaryAction / secondaryAction take your router's buttons or links, errorId shows a copyable error ID, autoFocus moves focus to the heading. ErrorBoundary catches render errors and shows a 500 page with Try again, or "A new version is available" with Reload when a lazily loaded file fails after a deploy; fallback, onError and resetKeys customise it. Also exported: isChunkLoadError, statusPageCopy.

Patch Changes

  • Untrusted content can no longer stall or crash the page (#165). Markdown and StreamingMarkdown cap nesting (32 block levels, 16 inline levels) and stop scanning unclosed brackets and emphasis markers early: deeply nested quotes or emphasis used to ...
Read more

@yugen-ui/cli 0.7.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 00:39
94c96c9

@yugen-ui/cli 0.7.0 and create-yugen-ui 0.7.0.

  • doctor reports React 18 as an error: yugen-ui 0.15 needs React 19 or later.
  • Template docs reads its pages with React.use.
  • Vite templates use TypeScript 7 (^7.0.2, the native compiler): npm run build type-checks several times
    faster. next-starter stays on TypeScript 6, because next build type-checks through TypeScript's JavaScript API.
  • Vite templates catch render errors with ErrorBoundary from yugen-ui 0.15: a page that fails shows a status page with
    Try again (or Reload when a file failed to load after a deploy) instead of a blank screen. saas and starter show
    a 404 page for unknown paths instead of the home page, and landing writes a static 404.html at build time.

Full notes: packages/cli/CHANGELOG.md · News

yugen-ui 0.14.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 16:59
4674b91

Minor Changes

  • New AppShell (#161): the frame of an app, with AppShellHeader, AppShellMain, AppShellAside, AppShellFooter and a Sidebar (SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarTrigger, SidebarRail). From breakpoint up (a container query on the shell, named app-shell) the sidebar sits in the layout and collapses to an icon rail (collapsible="icon", Nav labels move to Tooltips) or hides ("offcanvas"); below it the same content opens in a Drawer that closes when a link is followed or a Nav item is chosen. layout="header" puts the top bar across the full width with the sidebar below it; scroll="page" lets the whole page scroll with a sticky top bar and sidebar, for content sites (the top bar height is --app-shell-header). Sidebar resizable turns SidebarRail into a keyboard-operable splitter. Ctrl+B / ⌘B toggles the sidebar (shortcut), except in text fields, contenteditable and during IME composition; with several AppShells on a page only the one that has focus or was clicked last responds, and SidebarTrigger shows the label and the shortcut in its Tooltip. persistKey keeps the collapsed state and width in a cookie (read it on the server with readAppShellCookie); the Drawer is never saved. When the frame crosses the breakpoint with the Drawer open, it closes and focus returns to the trigger, or to the main region if the trigger is hidden. Skip link to the main region, useAppShell() for custom parts, strings in messages.appShell. NavItem gains tooltip. The SaaS, Dashboard, AI chat, Admin, Docs, Store, Blog, Landing and Starter templates use it. Thanks @dave-otf!

  • New yugen-ui/theme-core.css and yugen-ui/sources/<Component>.css (#169). theme.css makes Tailwind scan every component, so every app ships the CSS of all of them. theme-core.css is the same theme without that scan: add one @import "yugen-ui/sources/<Folder>.css" per component the app uses; each file also covers the components it uses inside (SplitButton.css includes Menu and Button). yugen-ui/sources/index.json maps every export to its file. On the templates this takes CSS from about 25 kB to 14–19 kB gzip. theme.css stays the zero-config default.

  • New Markdown (#263): renders static Markdown (articles, release notes, CMS fields) with Prose typography, through the same safe parser as StreamingMarkdown (no HTML, javascript: and data: links keep only their label). Code fences use CodeBlock, tables scroll inside a labelled region, task lists read "Done" / "Not done". inline renders inline Markdown only, in a <span>, for list items and table cells. Relative links (/path, #id) are kept and external links open in a new tab; renderLink hands every link to the app's router. headingOffset (default 1, so # is h2), headingIds (ids from the heading text, slugifyHeading), breaks, size. Strings in messages.markdown. parseMarkdown gains a relativeLinks option (off by default, so StreamingMarkdown still keeps absolute links only), parseInlineMarkdown parses one line, and sanitizeHref takes { relative: true }.

  • Breaking: built-in strings are English by default. Components show and announce English text ("Close", "Loading…", chart descriptions, live announcements) unless you pass messages, and locale defaults to "en-US" (dates, times, numbers, and a 12-hour TimePicker). For Vietnamese, as before: <YugenProvider messages={messagesVi} locale="vi-VN">. New messagesVi and per-component …MessagesVi for copied source; …Messages without a suffix stays the Vietnamese set so existing imports keep working, and messagesEn / …MessagesEn are the defaults. Helpers follow the same defaults: formatFileSize, validateFiles, the NotificationCenter time formatters, TimePicker's getDefaultHourCycle / formatTime / parseTimeString, and the DatePicker range presets.

  • New shared hooks, the ones the components use themselves (#172): useControllableState, useDisclosure, useLocalStorage (synced across hooks with the same key and across tabs; serialize / deserialize for keys that are not JSON), useClipboard, useHotkeys (mod is ⌘ on Apple and Ctrl elsewhere; skips form fields, IME composition and held keys; start / end arrows follow RTL), useDebouncedValue, useIntersection and useElementSize (measures before the first paint). useMediaQuery moves next to them; importing it from yugen-ui or from Sheet still works. Docs page "Hooks". Thanks @giabao12-hali!

    Components now use them instead of their own copies, with no visible change: controlled / uncontrolled state goes through useControllableState in every component except Sheet's snap point and Trace's auto-expand (a callback is no longer called when the value does not change, for example useTour().start() while the tour is already open), charts measure with useElementSize, the copy buttons use useClipboard and now report a refused copy instead of showing "Copied", and PackageManagerTabs keeps its saved choice through useLocalStorage.

  • New Sortable (#175): Sortable, SortableItem, SortableHandle and SortableGroup reorder lists with a mouse, pen, finger or the keyboard (Space or Enter on the handle picks the item up, arrow keys move it, Space or Enter drops it, Escape cancels), and announce every step through useAnnounce. Without dragging, click a handle to pick its item up and another item's handle to put it there. Vertical, horizontal (RTL-aware) and grid lists; SortableGroup moves items between lists (Kanban columns); the nearest scroll container scrolls near its edges; items slide into place unless reduced motion is on. onValueChange runs during the drag, onSortEnd once on drop. SortableItem handle makes the whole item the drag source and shortcuts moves it with Alt + arrow keys, for items that already use Space / Enter. arrayMove helper, strings in messages.sortable. Written in-house: about 6.5 kB gzip, no drag-and-drop dependency. DataGrid gains columnOrder (and getOrderedColumns); DataGridColumnPicker reorders columns when onColumnOrderChange is set (drag an item or Alt + ↑ ↓). TagPicker gains reorderable.

Patch Changes

  • CodeTabs and PackageManagerTabs: className now sizes the outer box. A w-full block inside a flex row (a centered demo, a card) used to keep the width of its tab bar and code and run past a narrow screen; it now fits and the tabs wrap.

Full notes: CHANGELOG.md · News

@yugen-ui/cli 0.6.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 17:02
4674b91

@yugen-ui/cli 0.6.0 and create-yugen-ui 0.6.0.

  • Breaking: requires Node.js 24 or newer. Yugen UI supports the two newest Node.js LTS lines (24 and 26 today).
  • Templates starter, saas, blog, dashboard, ai-chat, admin, docs, store and landing are built on
    AppShell from yugen-ui 0.14.0: collapsible sidebar (icon rail, Drawer on narrow screens), Ctrl+B / ⌘B, skip link.
  • Template admin: Board page (Kanban) with Sortable, saved on drop, rolled back with a toast when the request fails.

Full notes: packages/cli/CHANGELOG.md · News

yugen-ui 0.13.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 12:46
051c7e5

Minor Changes

  • Glass, part 2 (Yugen Labs). MenuPopover and PopoverSurface with material grow out of the button that opens them and shrink back into it when they close (scale and position from the trigger, read when the animation starts); with reduced motion they keep the plain fade. New material="glass" on Slider and Switch: while pressed or dragged the thumb turns to glass, larger on Slider so the track shows through it, longer on Switch. Names may change before 1.0.

  • New GlassRefraction (Yugen Labs): render it once at the app root and the edges of every glass, glass-clear and glass-tinted surface bend what is behind them, like the rim of a lens, while the middle stays frosted so text keeps its contrast. Each size and corner radius gets one SVG filter (a displacement map from Snell's law over a convex rim), applied through backdrop-filter; only Chromium browsers draw it, Safari and Firefox keep the regular glass. It turns off wherever the blur does (Reduce transparency, Increase contrast, forced colors, the high-contrast theme, glass inside glass) through the new --glassLensFilter token. Names may change before 1.0.

  • New Sonner: notifications that stack in a corner, newest in front, and fan out into a list on hover or keyboard focus. Call sonner("…"), sonner.success / info / warning / error / loading from anywhere; sonner.promise turns a loading notification into success or error in place, and calling again with the same id updates it. Action and cancel buttons, richColors, closeButton, swipe to dismiss, F8 to reach the region. Built on Radix Toast, no new dependency. Strings in messages.sonner.

    New display components (#174): Timeline / TimelineItem (detailed and compact), DescriptionList / DescriptionItem (columns that drop on narrow containers, inline layout, copy button; strings in messages.descriptionList), Stat (the stable version of StatTile, with a chart slot; strings in messages.stat) and Prose (typography for Markdown and CMS HTML through the new yugen-prose theme utility, zero-specificity selectors, opt out with not-prose). StatTile is now Stat plus a Sparkline and reads messages.stat; messages.chart.increase / decrease / noChange are deprecated. CodeBlock, Table, Quote and Timeline carry not-prose.

Patch Changes

  • Checkbox, Switch and Field: inside a <form>, the hidden input (or the hidden <select> of Dropdown) that Radix adds for form submission stays inside the control. It used to escape a scrolling container and add blank space at the bottom of the page.
  • Notice: React 18.3 stays supported for the rest of 0.x; from 1.0, Yugen UI supports React 19 only. Apps still on React 18 should move to React 19 before updating to 1.0.

Full notes: CHANGELOG.md · News

@yugen-ui/cli 0.5.1

Choose a tag to compare

@github-actions github-actions released this 28 Oct 12:48
051c7e5

@yugen-ui/cli 0.5.1 and create-yugen-ui 0.5.0.

  • Template glass: cherry blossom trips in Kyoto, Tokyo, Hirosaki and around Mount Fuji (photos from Wikimedia Commons,
    credited with their license), <GlassRefraction /> at the app root, a Settings preview of the bars over a bright,
    a blossom and a night photo, and a world map on Explore with every trip pinned at its coordinates.
  • Templates blog and docs: Markdown articles are styled with Prose from yugen-ui instead of classes on every tag.

Full notes: packages/cli/CHANGELOG.md · News

yugen-ui 0.12.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 11:59

Minor Changes

  • DataGrid: people can choose which columns are shown. The new hiddenColumns prop hides columns; DataGridColumnPicker is the "Columns" button that edits it, and it also works with Table. The menu stays open while columns are checked, a hideable: false column and the last visible column can't be hidden, and the sorted column keeps sorting the rows (with an arrow in the menu) while hidden. Hidden columns keep their resized width, pinned columns are re-measured, and keyboard focus stays on the same column instead of the same index. Columns can now set label instead of renderHeaderCell. useDataGridColumnVisibility and getVisibleColumns expose the logic.

    Menu: long menus scroll inside the viewport instead of overflowing it, and MenuItemCheckbox / MenuItemRadio accept secondaryContent like MenuItem.

  • Glass (Yugen Labs): a translucent material for the navigation layer that floats above content, inspired by Liquid Glass. Turn it on per component with material="glass" | "glass-clear" on Toolbar, TabsList, Nav, MenuPopover, PopoverSurface, TooltipContent, DialogSurface, DrawerSurface and SheetContent, appearance="glass" | "glass-prominent" on Button and appearance="glass" on Input / SearchBox. TabsList gets minimized and the useScrollMinimize hook for tab bars that shrink while scrolling down. New utilities: glass, glass-clear, glass-tinted, glass-scrim, scroll-edge, scroll-edge-above, rounded-concentric. Text keeps 4.5:1 over any backdrop; glass turns opaque with reduced transparency, increased contrast, the high-contrast theme, forced colors or without backdrop-filter. Names may change before 1.0.

Patch Changes

  • ContextMenu, Menubar and every submenu scroll inside the viewport when they are long, like Menu. On touch screens, where there is no hover, Table row actions, subtle selection checkboxes (Table and DataGrid) and Tree item actions are always visible. DataGrid and Table use tabular figures, so numbers line up in a column.

Full notes: CHANGELOG.md · News

@yugen-ui/cli 0.5.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 12:35
dd9e668

@yugen-ui/cli 0.5.0 and create-yugen-ui 0.5.0.

  • New template: glass (create --template glass), a travel journal with glass navigation over photos.
  • New template: landing (create --template landing), a product landing page with pricing, FAQ and a sign-up
    form; the first screen and the SEO tags are written into index.html at build time.
  • New template: admin (create --template admin), customers and orders with a server-paged DataGrid, drawer forms
    with validation, optimistic updates, and sign-in with a one-time code.
  • New template: next-starter (create --template next-starter), a Next.js App Router project with the theme in a
    cookie so the server renders it. create --lang works without an index.html.
  • New template: docs (create --template docs), a documentation site built from Markdown files, with Ctrl K search
    and an HTML file for every page.
  • New template: store (create --template store), a small shop with filters kept in the URL, a cart in a Sheet and a
    validated multi-step checkout; prices in US dollars, or dong with --lang vi.
  • Templates pin yugen-ui@^0.12.0. The SaaS template uses real paths (/analytics) instead of #/analytics, and the
    single-page templates ship deploy configs: public/_redirects (Netlify), vercel.json and npm run build:gh-pages
    (GitHub Pages).

Full notes: packages/cli/CHANGELOG.md · News