0.13.10 • Published 1 year ago

dialogic-react v0.13.10

Weekly downloads
8
License
MIT
Repository
-
Last release
1 year ago

Dialogic for React and NextJS

API

See: Main documentation

Demos

Codesandbox examples:

Demo code in this repo:

  • ./packages/demo-dialogic-react
  • ./packages/demo-dialogic-react-router

Installation

npm install dialogic-react

Usage

Dialog

// index.jsx
import React from "react";
import { dialog, Dialog } from "dialogic-react";

const App = () => (
  <>
    <button type="button" onClick={() => {
      dialog.show({
        dialogic: {
          component: DialogView, // any component; see example below
          className: "dialog",
        },
        title: "Dialog Title"
      })
    }}>
      Show dialog
    </button>
    <Dialog /> {/* dialog will be drawn by this component */}
  </>
);

const DialogView = props => (
  <div className="dialog">
    <div className="dialog-background" onClick={() => dialog.hide()}></div>
    <div className="dialog-content">
      <h3>{props.title}</h3>
      <div>Dialog content</div>
    </div>
  </div>
);
/* index.css */
.dialog {
  transition: opacity 350ms ease-in-out;
  opacity: 0;
}
.dialog-show-start {}
.dialog-show-end {
  opacity: 1;
}
.dialog-hide-start {}
.dialog-hide-end {
  opacity: 0;
}

Notification

// index.jsx
import React from "react";
import { notification, Notification, useDialogicState } from "dialogic-react";

const App = () => (
  <>
    <button type="button" onClick={() => {
      notification.show({
        dialogic: {
          component: NotificationView, // any component; see example below
          className: "notification",
        },
        title: "Notification Title"
      })
    }}>
      Show notification
    </button>
    <Notification /> {/* notification will be drawn by this component */}
  </>
);

const NotificationView = props => {
  useDialogicState(); // required to retrieve the current state
  return (
    <div className="notification">
      <div className="notification-content">
        <h3>{props.title}</h3>
        <>
          <span>Message</span>
          
          {/* Optionally using pause/resume/isPaused: */}
          <button type="button" onClick={() => {
            notification.isPaused()
              ? notification.resume({ minimumDuration: 2000 })
              : notification.pause()
          }}>
            {notification.isPaused()
              ? <span>Continue</span>
              : <span>Wait</span>
            }
          </button>
        </>
      </div>
    </div>
  );
};
/* index.css */
.notification {
  transition: opacity 350ms;
  opacity: 0;
}
.notification-show-start {}
.notification-show-end {
  opacity: 1;
}
.notification-hide-start {}
.notification-hide-end {
  opacity: 0;
}

useDialog

See also: useNotification and useDialogic.

In the following example the dialog is shown when the URL location matches the given path:

import { useDialog } from 'dialogic-react';
import { MyDialog } from './MyDialog';

const MyComponent = () => {
  const returnPath = '/';
  const dialogPath = '/some-path';
  const isRouteMatch = window.location.pathname === dialogPath;

  useDialog({
    isShow: isRouteMatch,
    props: {
      dialogic: {
        component: MyDialog,
        className: 'dialog',
      },
      // Props that will be passed to the MyDialog component
      returnPath,
    }
  });
};

With TypeScript

useDialog has a generic type to match the values passed to the component.

import { MyDialog, TDialogProps } from './MyDialog';

const returnPath = '/';
const dialogPath = '/some-path';
const content = 'Some async loaded content';
const isRouteMatch = window.location.pathname === dialogPath;

useDialog<TDialogProps>({
  isShow: isRouteMatch && !!content,
  deps: [content],
  props: {
    dialogic: {
      component: MyDialog,
      className: 'dialog',
    },
    // Props that will be passed to the MyDialog component
    // These props match type TDialogProps
    returnPath,
    content,
  }
})

Calling show and hide directly

In the example below:

  • show is used to show the dialog
  • Component MyDialog receives props hideDialog to explicitly hide the dialog
  • deps includes the URL location - whenever it changes the dialog is hidden
import { useDialog } from 'dialogic-react';
import { MyDialog } from './MyDialog';

const MyComponent = () => {
  const { show, hide } = useDialog({
    deps: [window.location.href], // as soon this value changes ...
    hide: true,                   // ... hide
    props: {
      dialogic: {
        component: MyDialog,
        className: 'dialog',
      },
      // Props that will be passed to the MyDialog component
      returnPath,
      hideDialog: () => hide(),
    }
  });

  return (
    <button type="button" onClick={() => show()}>Show dialog</button>
  )
};

With React Router 5

An example with React Router 6 and UseDialog component is listed further on the page

Use react-router matching for more flexibility on matching routes. This can also be used to match on parametrized routes.

See also CodeSandbox demo: Route example with useDialog.

import { useRouteMatch } from 'react-router-dom';

const dialogPath = '/profile/:name';
const matchDialogPath = useRouteMatch(dialogPath);

useDialog({
  isShow: !!matchDialogPath,
  ...
});

To only show the dialog on exact matches:

useDialog({
  isShow: matchDialogPath ? matchDialogPath.isExact : false,
  ...
});

UseDialog component

Helper component that wraps useDialog to use in JSX syntax, for example together with React Router.

It accepts the same props as useDialog.

UseDialog component with React Router 6

// ProfilePage.tsx
import { UseDialog } from 'dialogic-react';
import {
  Outlet,
  Route,
  Routes,
  useLocation,
  useNavigate,
  useResolvedPath,
} from 'react-router-dom';
import {
  EditProfileDialog,
  EditProfleDialogProps,
} from '../components/EditProfileDialog';

// Separate function for separation of concerns
function useEditProfileDialogProps(dialogFragment: string) {
  const location = useLocation();
  const navigate = useNavigate();
  const url = useResolvedPath('').pathname;
  const dialogPath = `${url}/${dialogFragment}`;
  const dialogReturnPath = url;
  const isExactMatch = location.pathname === dialogPath;

  const dialogProps = {
    dialogic: {
      component: EditProfileDialog,
      className: 'edit-profile-dialog',
    },
    // ... additional props to pass to EditProfileDialog
  };

  return {
    dialogPath,
    isExactMatch,
    dialogProps,
  };
}

function ProfilePage() {
  return (
    <div>
      <h1>Profile</h1>
      <p>Profile data</p>
      <Outlet />
    </div>
  )
}

export function ProfileRoutes() {
  const dialogFragment = 'edit';
  const { isExactMatch, dialogProps, dialogPath } = useEditProfileDialogProps(dialogFragment);

  return (
    <Routes>
      <Route path='*' element={<ProfilePage />}>
        <Route
          path={dialogFragment}
          element={<UseDialog<MyDialogProps> props={dialogProps} />}
        />
      </Route>
    </Routes>
  );
}

// App.tsx
import { Dialog, Notification } from 'dialogic-react';
import React from 'react';
import { HashRouter as Router, Route, Routes } from 'react-router-dom';

import { HomePage } from './pages/HomePage';
import { ProfileRoutes } from './pages/ProfilePage';

function AppRoutes() {
  return (
    <Router>
      <Routes>
        <Route path='/' element={<HomePage />} />
        <Route
          path='/profile/*'
          element={<ProfileRoutes />}
        />
      </Routes>
      {/* Placing Notification and Dialog here allows to use Link components inside instances: */}
      <Notification />
      <Dialog />
    </Router>
  );
}

export default function App() {
  return (
    <div className='app'>
      <AppRoutes />
    </div>
  );
}

UseDialog component with React Router 5

See also CodeSandbox demo: Route example with UseDialog

import { Route, useHistory } from 'react-router-dom';
import { UseDialog } from 'dialogic-react';
import { MyDialog } from './MyDialog';

export const MyDialogRoute = () => {
  const history = useHistory();
  const dialogPath = '/some-path';
  const returnPath = '/';
  const content = 'Some async loaded content';
  const isRouteMatch = history.location.pathname === dialogPath;

  return (
    <Route path={dialogPath}>
      <UseDialog
        show={isRouteMatch && !!content}
        deps={[content]}
        props={{
          dialogic: {
            component: MyDialog,
            className: 'dialog',
          },
          // Props that will be passed to the MyDialog component
          returnPath,
          content,
        }}
      />
    </Route>
  )
};

With TypeScript

import { Route, useHistory } from 'react-router-dom';
import { UseDialog } from 'dialogic-react';
import { MyDialog, TDialogProps } from './MyDialog';

export const MyDialogRoute = () => {
  const history = useHistory();
  const dialogPath = '/some-path';
  const returnPath = '/';
  const content = 'Some async loaded content';
  const isRouteMatch = history.location.pathname === dialogPath;

  return (
    <Route path={dialogPath}>
      <UseDialog<TDialogProps>
        show={isRouteMatch && !!content}
        deps={[content]}
        props={{
          dialogic: {
            component: MyDialog,
            className: 'dialog',
          },
          // Props that will be passed to the MyDialog component
          // These props match type TDialogProps
          returnPath,
          content,
        }}
      />
    </Route>
  )
};

useDialogicState

To retrieve the current state in a component, add hook useDialogicState:

import { dialog, useDialogicState } from "dialogic-react";

const MyComponent = props => {
  useDialogicState();

  return (
    <div>{dialog.getCount()}</div>
  )
}

useRemaining

Hook to fetch the current remaining time.

import { notification, useDialogicState, useRemaining } from "dialogic-react";

const MyComponent = props => {
  useDialogicState();
  const [remainingSeconds] = useRemaining({ instance: notification, roundToSeconds: true });
  // ...
}

Sizes

┌────────────────────────────────────────────┐
│                                            │
│   Bundle Name:  dialogic-react.module.js   │
│   Bundle Size:  35.01 KB                   │
│   Minified Size:  17.53 KB                 │
│   Gzipped Size:  5.65 KB                   │
│                                            │
└────────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│                                         │
│   Bundle Name:  dialogic-react.umd.js   │
│   Bundle Size:  38.23 KB                │
│   Minified Size:  14.92 KB              │
│   Gzipped Size:  5.24 KB                │
│                                         │
└─────────────────────────────────────────┘

┌──────────────────────────────────────┐
│                                      │
│   Bundle Name:  dialogic-react.cjs   │
│   Bundle Size:  35.36 KB             │
│   Minified Size:  17.89 KB           │
│   Gzipped Size:  5.69 KB             │
│                                      │
└──────────────────────────────────────┘
0.13.7

1 year ago

0.13.10

1 year ago

0.13.6

2 years ago

0.13.5

2 years ago

0.13.4

2 years ago

0.13.1

3 years ago

0.13.2

3 years ago

0.13.3

3 years ago

0.13.0

3 years ago

0.12.7

3 years ago

0.12.6

3 years ago

0.12.4

3 years ago

0.12.5

3 years ago

0.12.0

3 years ago

0.12.1

3 years ago

0.12.2

3 years ago

0.12.3

3 years ago

0.11.0

4 years ago

0.10.3

4 years ago

0.10.2

4 years ago

0.10.1

4 years ago

0.9.1

4 years ago

0.9.0

4 years ago

0.8.5

4 years ago

0.8.4

4 years ago

0.8.3

4 years ago

0.8.2

4 years ago

0.8.1

4 years ago

0.8.0

4 years ago

0.7.1

4 years ago

0.7.0

4 years ago

0.6.1

4 years ago

0.6.0

4 years ago

0.5.4

4 years ago

0.5.3

4 years ago

0.5.2

4 years ago

0.5.1

4 years ago

0.4.10

4 years ago

0.4.9

4 years ago

0.4.8

4 years ago

0.4.7

4 years ago

0.4.6

4 years ago

0.4.5

4 years ago

0.4.4

4 years ago

0.4.1

4 years ago

0.4.0

4 years ago

0.4.3

4 years ago

0.4.2

4 years ago

0.3.2

4 years ago

0.3.1

4 years ago

0.3.0

4 years ago

0.2.3

4 years ago

0.2.1

4 years ago

0.2.0

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago