mubanjs / muban

A standalone library for creating a single muban component
https://mubanjs.github.io/muban/
MIT License
9 stars 6 forks source link

Add user-defined `propType.source` for fallback cases #66

Closed ThaNarie closed 2 years ago

ThaNarie commented 2 years ago

Currently the propType.source api only allows extracting values that Muban supports. There is no way for a user to extract something else.

If we allow for a user-defined function, we have an escape hatch for users, and if we see commonly used patterns, we can could include the as a default source type.

Proposal:

// still supports the `target` to access earlier defined refs
// if `target` is omitted, it will pass the component element
// the user function should be located inside the `options` to fit the current structure
propType.source({ target: 'refName', options: { fn: (element: HTMLElement) => T } });

// and/or
// a way simpler API, but loses access to the `ref`
propType.source((element: HTMLElement) => T);

// we could provide the resolved refs as a 2nd parameter?
propType.source((element: HTMLElement, refs: TypedRefs) => T);

@ThijsTyZ Any opinions / suggestions?

ThijsTyZ commented 2 years ago

Can we maybe do a combination of both?

// still supports the `target` to access earlier defined refs
// the user function should be located inside the `options` to fit the current structure
// provide the targetElement, componentElement and the refs. In case the target is not set, targetElement is omitted
propType.source({ target: 'refName', options: { fn: (componentElement: HTMLElement, refs?: TypedRefs, targetElement?: HTMLElement,) => T } });

// and

propType.source((componentElement: HTMLElement, refs?: TypedRefs) => T);
ThijsTyZ commented 2 years ago

And perhaps change it to an options argument for the function so the order doesn't matter.

ThaNarie commented 2 years ago

Unfortunately, most of your suggestions aren't really possible. I did update the generic version with an options object. And I think both versions could exist simultaneously.

Open question still:

It would then look something like this:

// still supports the `target` to access earlier defined refs
// if `target` is omitted, it will pass the component element
// the customSource function should be located inside the `options` to fit the current structure
propType.source({
  target: 'refName',
  options: {
    // `element` refers to the resolved `target`, or the "component root element" when no target is specified
    customSource: (element: HTMLElement | Array<HTMLElement> | undefined) => T
  }
});

// a way simpler API, but loses access to the `ref`, so all responsibility is for the implementor
// we can pass all the refs here, but they cannot be typed to match the ref definitions of the component.
propType.source(
  ({ componentElement: HTMLElement, refs: Record<string, HTMLElement | Array<HTMLElement>> }) => T
);