Skip to content

Commit

Permalink
feat: add possibility to decorate components
Browse files Browse the repository at this point in the history
#11472 brought up a gap we have with the new API currently: There's no way to decorate a component right now. With the old class syntax this was straightforward because you would extend the class and for example modify the props on the way in. This adds `decorateComponent` to achieve the same.
  • Loading branch information
dummdidumm committed May 10, 2024
1 parent 641e411 commit 275fd2e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-planets-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 1,5 @@
---
"svelte": patch
---

feat: add possibility to decorate components
20 changes: 20 additions & 0 deletions packages/svelte/src/index-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 180,26 @@ export function flushSync(fn) {
flush_sync(fn);
}

/**
* Wraps a component with a decorator that is able to modify the props of the component before it is created.
* @template {import('svelte').SvelteComponent} Component
* @template {import('svelte').ComponentProps<Component>} [Props=import('svelte').ComponentProps<Component>]
* @param {Component} component
* @param {(args: { props: Props, component: (props: Props) => Component }) => Component} decorator
* @returns {Component}
*/
export function decorateComponent(component, decorator) {
// @ts-expect-error shape is different under the hood
return (target, props) => {
return decorator({
props,
component: (props) =>
// @ts-expect-error shape is different under the hood
component(target, props)
});
};
}

export { hydrate, mount, unmount } from './internal/client/render.js';

export {
Expand Down
19 changes: 19 additions & 0 deletions packages/svelte/src/index-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 34,23 @@ export function unmount() {

export async function tick() {}

/**
* @template {import('svelte').SvelteComponent} Component
* @template {import('svelte').ComponentProps<Component>} [Props=import('svelte').ComponentProps<Component>]
* @param {Component} component
* @param {(args: { props: Props, component: (props: Props) => Component }) => Component} decorator
* @returns {Component}
*/
export function decorateComponent(component, decorator) {
// @ts-expect-error shape is different under the hood
return (payload, props) => {
return decorator({
props,
component: (props) =>
// @ts-expect-error shape is different under the hood
component(payload, props)
});
};
}

export { getAllContexts, getContext, hasContext, setContext } from './internal/server/context.js';
7 changes: 7 additions & 0 deletions packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 304,13 @@ declare module 'svelte' {
* Synchronously flushes any pending state changes and those that result from it.
* */
export function flushSync(fn?: (() => void) | undefined): void;
/**
* Wraps a component with a decorator that is able to modify the props of the component before it is created.
* */
export function decorateComponent<Component extends SvelteComponent<Record<string, any>, any, any>, Props extends ComponentProps<Component> = ComponentProps<Component>>(component: Component, decorator: (args: {
props: Props;
component: (props: Props) => Component;
}) => Component): Component;
/** Anything except a function */
type NotFunction<T> = T extends Function ? never : T;
/**
Expand Down

0 comments on commit 275fd2e

Please sign in to comment.