Skip to content

refactor(dify-ui): finish primitive migration from web/base/ui to @langgenius/dify-ui#35349

Merged
lyzno1 merged 25 commits intomainfrom
cursor/migrate-base-ui-to-dify-ui
Apr 17, 2026
Merged

refactor(dify-ui): finish primitive migration from web/base/ui to @langgenius/dify-ui#35349
lyzno1 merged 25 commits intomainfrom
cursor/migrate-base-ui-to-dify-ui

Conversation

@lyzno1
Copy link
Copy Markdown
Member

@lyzno1 lyzno1 commented Apr 17, 2026

Summary

Finishes the incremental move of every atomic UI primitive from web/app/components/base/ui/* to @langgenius/dify-ui. After this PR web/app/components/base/ui/ no longer exists.

Full component list now under dify-ui (14 primitives + shared helpers):
alert-dialog, avatar, button, context-menu, dialog, dropdown-menu, number-field, popover, scroll-area, select, slider, switch, toast, tooltip.

Package shape — source subpath exports, one subpath per component (@langgenius/dify-ui/<comp>). No build step in this phase; future npm publishing only needs to point exports at a tsdown dist.

Props pattern (consistent across all 14 components):

Omit<BaseXxx.Root.Props, 'className' | ...> & VariantProps<typeof xxxVariants> & { /* custom */ }

Native HTML attrs, ref, aria-*, data-*, form integration come from base-ui for free; only design decisions (variants, className merge, opinionated callback signatures) are owned by dify-ui.

Tooling / CI bootstrapped

  • vitest + happy-dom + @testing-library; dedicated dify-ui-test CI job with v8 coverage uploaded to Codecov under flag dify-ui
  • Storybook stories glob extended to ../../packages/dify-ui/src/**
  • Tailwind content scans packages/dify-ui/src/**
  • peer / dep / devDep split; @dify/tsconfig/react.json introduced so dify-ui does not extend web-flavored configs
  • codecov.yml gains dify-ui flag, removed_code_behavior: adjust_base, and a 1% threshold so refactor PRs are not flagged by sub-percent noise

API-debt resolution — overlay primitives (popover, tooltip, select, dropdown-menu, context-menu) each export type { Placement } from their own index; no consumer imports the internal placement.ts / overlay-shared.ts via a standalone subpath. Those two subpath exports are removed from package.json#exports; the files remain as internal implementation.

Codemod — ~2600 web consumer lines rewritten from @/app/components/base/ui/<x> to @langgenius/dify-ui/<x>, including all vi.mock sites (key and path). A handful of stale relative imports (../../ui/..., ./components/base/ui/...) were repaired.

Non-mechanical items

  • scroll-area/index.stories.tsx replaced its <AppIcon> usage with a neutral <div> placeholder since AppIcon is a web-only business component.

Verification

  • vp run -r type-check — 5 workspaces green
  • packages/dify-ui — 14 spec files / 180 tests green; coverage emitted and uploaded to Codecov under flag dify-ui
  • web — 2332 spec files / 28698 tests / 2 skipped, all green
  • eslint --fix packages/dify-ui/src/**/*.{ts,tsx} — 0 errors

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

From Cursor Agent

…ggenius/dify-ui

- Bootstrap dify-ui tooling: vitest config, test setup, peer/dev deps, storybook types
- Extend web tailwind content and storybook stories glob to scan packages/dify-ui/src
- Add dify-ui-test job in web-tests workflow
- Introduce @dify/tsconfig/react.json as a framework-neutral React base (used by dify-ui; nextjs.json now extends it; old web.json removed)
- Migrate shared overlay helpers (placement, overlay-shared) plus avatar and slider components as source subpath exports
- Codemod all consumers from @/app/components/base/ui/{avatar,slider,placement,overlay-shared} to @langgenius/dify-ui/<sub>

Made-with: Cursor
@github-actions github-actions Bot added the web This relates to changes on the web. label Apr 17, 2026
Comment thread packages/dify-ui/AGENTS.md
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.47%. Comparing base (bd25240) to head (c3e2dbe).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #35349      +/-   ##
==========================================
- Coverage   85.48%   85.47%   -0.01%     
==========================================
  Files        4428     4429       +1     
  Lines      206408   206407       -1     
  Branches    38340    38339       -1     
==========================================
- Hits       176438   176431       -7     
- Misses      26860    26866       +6     
  Partials     3110     3110              
Flag Coverage Δ
dify-ui 92.51% <100.00%> (?)
web 86.41% <ø> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lyzno1 and others added 10 commits April 17, 2026 13:08
…ot a standalone subpath

- Each overlay primitive (popover, tooltip, select, dropdown-menu, context-menu) now re-exports `type Placement` from its own index
- The 3 external wrappers (operation-dropdown, plugin-version-picker, select-metadata-modal) import `type Placement` from the overlay component they actually use
- Fix two stories that still referenced the old `../placement` path
- Document the API debt in packages/dify-ui/AGENTS.md: `./placement` and `./overlay-shared` subpath exports are internal transition bridges, pending removal once overlay primitives migrate into packages/dify-ui/src/*

Type-only re-exports compile away under `verbatimModuleSyntax`, so the `no-barrel-files` rule is locally suppressed with a comment explaining why.

Made-with: Cursor
…/dify-ui/switch

- Copy switch to packages/dify-ui/src/switch; merge former skeleton.tsx into the same index.tsx (both Switch and SwitchSkeleton are named exports now)
- Drop React.memo / displayName; declare component at its definition site as a named export per the dify-ui authoring rules
- Tighten API: SwitchProps now extends base-ui's Switch.Root.Props (so ref, render, form integration are free), with size from CVA variants and a narrow onCheckedChange(checked) that matches the React setter shape. SwitchSkeletonProps extends HTMLAttributes<HTMLDivElement>
- Codemod all consumers: 53 default imports -> named imports from @langgenius/dify-ui/switch, 7 vi.mock blocks updated (path swap + `default:` -> `Switch:`, drop stale __esModule:true)
- Delete web/app/components/base/switch/
- Fix tsconfig leak: dify-ui had noEmit:false + outDir:dist which silently emitted dist/ on every type-check and polluted vitest runs; switch to noEmit for the source-export phase

Made-with: Cursor
- Add @vitest/coverage-v8 to dify-ui devDeps; configure v8 provider, scope to src/ and exclude stories/tests/styles
- codecov.yml: register a dify-ui flag pointing at packages/dify-ui/
- web-tests.yml dify-ui-test job now runs `--coverage` and calls codecov-action with flag=dify-ui
- Add packages/dify-ui/.gitignore for coverage/ and dist/

Made-with: Cursor
The loading-state toggle added to AppCard was bundled into an unrelated
CI/coverage commit; drop the app-card portion only and keep the rest.

Made-with: Cursor
@lyzno1 lyzno1 changed the title refactor(dify-ui): migrate avatar and slider from web/base/ui refactor(dify-ui): scaffold package + migrate avatar / slider / switch Apr 17, 2026
@lyzno1 lyzno1 marked this pull request as ready for review April 17, 2026 06:25
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Apr 17, 2026
@dosubot dosubot Bot added the refactor label Apr 17, 2026
lyzno1 added 5 commits April 17, 2026 14:28
…and refactor-friendly project status

- Migrate top-level `flags:` to `flag_management:` (default_rules + individual_flags; less repetition)
- Add global `ignore:` for .d.ts, stories, specs, configs, storybook, next/vite/test setup
- `project` status: add 1% threshold + `removed_code_behavior: adjust_base` so migrations deleting covered code don't regress the baseline
- `comment.layout` pinned to `diff, flags, files` (drop default `reach`)
- Pin `precision`, `round`, `range`, `require_ci_to_pass`, `notify.wait_for_ci` explicitly

Validated against https://codecov.io/validate.

Made-with: Cursor
… and removed_code_behavior

Made-with: Cursor
hyoban
hyoban previously approved these changes Apr 17, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Apr 17, 2026
@crazywoola
Copy link
Copy Markdown
Member

Maybe next version?

lyzno1 added 4 commits April 17, 2026 15:42
… toast (Wave A, independent leaves)

Made-with: Cursor
…cement and overlay-shared exports

- popover, tooltip, select, context-menu, dropdown-menu moved to packages/dify-ui/src/*
- Each rewrites placement/overlay-shared imports to relative paths (../placement, ../overlay-shared)
- no-barrel-files eslint-disable comments removed (rule is web-only, not needed in packages/)
- package.json exports: add 5 new subpaths, remove ./placement and ./overlay-shared (no external consumers remain; they stay as internal implementation files)
- web/app/components/base/ui/ now empty

Made-with: Cursor
@lyzno1 lyzno1 changed the title refactor(dify-ui): scaffold package + migrate avatar / slider / switch refactor(dify-ui): finish primitive migration from web/base/ui to @langgenius/dify-ui Apr 17, 2026
lyzno1 added 4 commits April 17, 2026 16:13
…i-to-dify-ui

Made-with: Cursor

# Conflicts:
#	web/app/components/workflow/nodes/_base/components/panel-operator/index.tsx
The storybook preview was still pointing at the removed
web/app/components/base/ui/toast path, causing knip to report an
unresolved import. Align it with app/layout.tsx which already uses the
dify-ui package.

Made-with: Cursor
@lyzno1 lyzno1 enabled auto-merge April 17, 2026 08:44
@lyzno1 lyzno1 added this pull request to the merge queue Apr 17, 2026
Merged via the queue into main with commit dfcc0f8 Apr 17, 2026
36 checks passed
@lyzno1 lyzno1 deleted the cursor/migrate-base-ui-to-dify-ui branch April 17, 2026 08:55
lyzno1 added a commit to lyzno1/dify that referenced this pull request Apr 17, 2026
Finish the follow-up to langgenius#35349 by replacing all remaining references to
the removed `app/components/base/ui/` path with `@langgenius/dify-ui`
across docs, ESLint config, deprecation notices, and incidental comments
and test descriptions. Also drop the now-dead `dify/base-ui-primitives`
ESLint override whose glob no longer matches any file.

Made-with: Cursor
lyzno1 added a commit to lyzno1/dify that referenced this pull request Apr 17, 2026
- New `packages/dify-ui/README.md`: documents the package scope, subpath
  import model, the Base UI portal behavior, the root `isolation: isolate`
  requirement, and the `z-1002` / `z-1003` layering — the permanent
  contract that should outlive the overlay migration.
- `web/docs/overlay-migration.md`, `web/AGENTS.md`: add pointers to the
  new dify-ui README so the permanent contract is discoverable and the
  migration doc can shrink over time.
- Replace the `base/button/index.spec.tsx` example reference (directory
  removed in langgenius#35349) with `base/radio/__tests__/index.spec.tsx`, which
  better matches the user-event / role-query patterns in `test.md`.
  Touches: `web/README.md`, `web/docs/test.md`, `web/scripts/analyze-component.js`,
  `.agents/skills/frontend-testing/SKILL.md`.
- `.agents/skills/frontend-testing/references/mocking.md`: broaden the
  "don't mock" guidance to cover both `@/app/components/base/*` and
  `@langgenius/dify-ui/*`, and fix code examples that imported from the
  removed `base/button` path.

Made-with: Cursor
HanqingZ pushed a commit to HanqingZ/dify that referenced this pull request Apr 23, 2026
…nggenius/dify-ui (langgenius#35349)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
asukaminato0721 pushed a commit to asukaminato0721/dify that referenced this pull request Apr 24, 2026
…nggenius/dify-ui (langgenius#35349)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update javascript code lgtm This PR has been approved by a maintainer refactor size:L This PR changes 100-499 lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants