Commit graph

4 commits

Author SHA1 Message Date
Merlijn Vos
fa23832f6a
@uppy/vue: support kebab-case props in generated components (#6125)
## Summary

- Fix Vue components to work with kebab-case props (`:edit-file` instead
of `:editFile`)
- Update `migrate.mjs` to parse prop names from TypeScript source files
and generate explicit `props` arrays

## Problem

The generated Vue components didn't work correctly with Vue's standard
kebab-case prop convention:

```vue
<!-- This didn't work -->
<FilesList :edit-file="handleEdit" />

<!-- Only this worked (non-standard) -->
<FilesList :editFile="handleEdit" />
```

## Root Cause

The original Vue template used `attrs` to pass props to Preact:

```ts
setup(props, { attrs }) {
  preactRender(preactH(PreactComponent, {
    ...(attrs as Props),  // attrs preserves kebab-case!
    ctx,
  }), container)
}
```

When using `:edit-file` in a Vue template, Vue passes
`attrs['edit-file']` (kebab-case preserved), but Preact expects
`editFile` (camelCase).

## Solution

Generate Vue components with explicit `props` declarations:

```ts
defineComponent({
  props: ['editFile', 'columns', 'imageThumbnail'],
  setup(props) {
    preactRender(preactH(PreactComponent, {
      ...props,  // Vue already converted kebab → camelCase
      ctx,
    }), container)
  }
})
```

When Vue components declare their props, Vue automatically converts
kebab-case template usage to camelCase in the `props` object. This is
standard Vue behavior.

## Why Simpler Alternatives Don't Work

### "Just use `props` instead of `attrs`"

Without a `props` declaration, Vue doesn't know which attributes are
props. The `props` object will be empty and everything goes to `attrs`:

```ts
// Without props declaration
defineComponent({
  setup(props, { attrs }) {
    // props = {}  (empty!)
    // attrs = { 'edit-file': fn }  (kebab-case preserved)
  }
})
```

### "Accept all props dynamically"

Vue doesn't have a "accept all props and convert casing" option. You
must explicitly declare which props you expect for Vue to handle the
conversion.

### "Just document to use camelCase"

This works but violates Vue conventions. Every Vue developer expects
`:edit-file` to work.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Prakash <qxprakash@gmail.com>
2026-01-19 09:59:42 +01:00
Mikael Finstad
075636a3b3
remove react h (#5938)
it was added in #5935 but no explanation of why.

if you look at the build output of for example
`packages/@uppy/react/lib/headless/generated/Dropzone.js`:

```js
import { jsx as _jsx } from "react/jsx-runtime";
// This file was generated by build-components.mjs
// ANY EDITS WILL BE OVERWRITTEN!
import { Dropzone as PreactDropzone, } from '@uppy/components';
import { h as preactH, render as preactRender } from 'preact';
// biome-ignore lint/correctness/noUnusedImports: it's needed
import { createElement as h, useContext, useEffect, useRef } from 'react';
import { UppyContext } from '../UppyContextProvider.js';
export default function Dropzone(props) {
    const ref = useRef(null);
    const ctx = useContext(UppyContext);
    useEffect(() => {
        if (ref.current) {
            preactRender(preactH(PreactDropzone, {
                ...props,
                ctx,
            }), ref.current);
        }
    }, [ctx, props]);
    return _jsx("div", { ref: ref });
}
```

as can be seen there is no usage of `h`. `import { jsx as _jsx } from
"react/jsx-runtime";` is being injected for React JSX. see also
https://github.com/transloadit/uppy/pull/5896#issuecomment-3169210799
2025-08-29 16:24:16 +02:00
Merlijn Vos
49522ec5cb
Remove preact/compat (#5935)
We drag it in unneccesarily in the bundle and it can cause JSX clashes
in React apps with `"jsx": "preserve"` in their `tsconfig.json`
(https://github.com/preactjs/preact/issues/4908)

- Remove `@types/react` from companion (unused)
- Fix tsconfig's for @uppy/utils (build was fine, but editor diagnostics
weren't)
2025-08-28 16:57:07 +02:00
Merlijn Vos
271db86ad0
Use turbo for building and watching concurrently (#5808)
- Add `typecheck` command to all packages.
- Use turbo to build and watch concurrently with caches.
- Remove root `bin/` folder with last global scripts
- `bin/companion.sh` -> `@uppy/companion/start-dev` (`yarn
start:companion` still works)
- `bin/build-components.mjs` -> `@uppy/components/migrate.mjs` (`yarn
migrate:components` can be used to run it). This only needs to be ran
for new components, not changing existing ones, so that's why it's not
part of the build process.

turbo is smart enough to build dependencies within a package first
before building the package itself (e.g if wanting to build @uppy/audio,
build @uppy/utils first). Unfortunately @uppy/core is a peer dep
everywhere turbo does not take it into account, yet it must be build
first to avoid race conditions. Therefor I added a turbo.json to each
package, which you normally never need, but this is an odd case I
suppose. Other solutions ran into cyclic dep errors.

Another PR would move over the test commands to turbo too.
2025-07-10 13:21:18 +02:00
Renamed from bin/build-components.mjs (Browse further)