Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to wrap Ionic components for use as higher order components (HOC)? #109

Open
ptmkenny opened this issue Aug 9, 2024 · 2 comments
Open

Comments

@ptmkenny
Copy link
Contributor

ptmkenny commented Aug 9, 2024

I'm trying to make an Ionic Svelte app, coming from Ionic React.

In React, I wrapped the ion-button component like this:

export type CustomIonButtonWrapper = {
  children: StringOrElementOrNumber | StringOrElementOrNumber[];
  onClick?:
    | ((event: React.FormEvent) => void)
    | (() => Promise<void>)
    | (() => void);
  routerLink?: string;
  id?: string;
  color?: 'danger' | 'tertiary' | 'warning' | 'success';
  type?: 'submit';
  href?: string;
  className?: string;
  fill?: 'outline';
  disabled?: boolean;
  role?: 'button' | 'link';
};

const ButtonStandard: React.FC<CustomIonButtonWrapper> = (
  props: IonicButtonWrapper,
) => {
  const { children, ...otherProps } = props;
  return (
    <IonButton size="small" {...otherProps}>
      {children}
    </IonButton>
  );
};

Here, I restricted the number of props that can be provided to ion-button by adding the CustomIonButtonWrapper type, and then set the button size to small.

This allows me to use the <ButtonStandard> component to control the ion-button component, ensuring I only use the specified props throughout my app.

How can I do something similar in Svelte? Specifically,

  1. Wrap ion-button in a Svelte component
  2. Enforce a custom type for my ButtonStandard component (do not accept all the props that ion-button does).

I came up with the following but it seems verbose compared to React. Is there a better way?

<script lang="ts">
	export let onClick:
		| ((event: MouseEvent) => void)
		| (() => Promise<void>)
		| (() => void)
		| undefined = undefined;
	export let id: string | undefined = undefined;
	export let color: 'danger' | 'tertiary' | 'warning' | 'success' | undefined = undefined;
	export let type: 'submit' | undefined = undefined;
	export let href: string | undefined = undefined;
	export let className: string | undefined = undefined;
	export let fill: 'outline' | undefined = undefined;
	export let role: 'button' | 'link' | undefined = undefined;
	export let disabled: boolean = false;
</script>

{#if id}
	<ion-button
		size="small"
		on:click={onClick}
		{id}
		{color}
		{type}
		{href}
		class={className}
		{fill}
		{role}
		{disabled}
	>
		<slot />
	</ion-button>
{:else}
	<!-- 
    If id is set to undefined, then Svelte sets id to the string "undefined".
    So if id has not been set, then do not set id (to avoid setting it to the string "undefined").
   -->
	<ion-button
		size="small"
		on:click={onClick}
		{color}
		{type}
		{href}
		class={className}
		{fill}
		{role}
		{disabled}
	>
		<slot />
	</ion-button>
{/if}

Related to #93 and #88.

This is an issue because this project offers ion-button as a web component rather than a Svelte component. I imagine it would be a lot of work (and painful maintenance) to make Svelte components for all the Ionic components. So I'm wondering if there's another way to wrap the web components to use them as HOC without creating Svelte components?

@Tommertom
Copy link
Owner

I dont think it is a lot of work to generate svelte components wrapping ionic (there are definition files in the ionic package you could use for that), but it is not a great idea as you lose two way binding and you cannot style the components directly with css anymore (encapsulation). I considered that in the beginning and it does not work for me.

I dont think there is anything else - webcomponents, for what I know, live in the browser as some sort of native thing. So your question is similar to asking if you can make a HOC of a div or a button.

Why do you want this?

@ptmkenny
Copy link
Contributor Author

ptmkenny commented Aug 9, 2024

Hmm. Is there a way to make both ion-button (as a web component) and IonButton (as a Svelte component) available?

In my React app, I use HOC for ion-button, ion-toggle, ion-range, ion-icon, and several others in conjunction with a "handedness" setting. Users can select if they are right- or left-handed, and then all the UI moves to the appropriate side of the screen. Because this can get pretty complicated (submit buttons should be on the same side as the user's dominant hand, whereas delete buttons should be on the reverse side), I did this by using my own components that wrap the Ionic components, which works really well and prevents me from setting the wrong value. So I was trying to do something similar in Svelte but it has turned out to be more complicated than React.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants