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

feat(useStepper): new function #1754

Merged
merged 14 commits into from Jul 6, 2022
Merged

feat(useStepper): new function #1754

merged 14 commits into from Jul 6, 2022

Conversation

innocenzi
Copy link
Contributor

useStepper

Note

This is an improved version of #1679, with which I was not happy. I've continued building wizards (steppers) in my application, and this composable is the result of what feels to me is perfect and flexible for most use cases.

This new implementation has better types and support both array and objects as steps.

Description

This new utility helps building step-based wizard user interfaces. This is something that I did repeatedly in one of our applications, and this is the actual composable I'm using.

The declaration of the steps is done via an array of strings, which serve as identifiers, or via an object, which keys serve as identifiers. The composable returns a set of computed values and functions that are very useful to navigate through the steps.

For instance, the goToPrevious and goToNext function move. Computed variables like isFirst, isLast or current help determining what to display. To display the component for the current step, one can use isCurrent('step name').

Example

The demo is a full example, and tests cover all functionalities, but here is what it looks like at a glance.

const stepper = useStepper({
  'user-information': {
    title: 'User information',
    isValid: () => form.firstName && form.lastName,
  },
  'billing-address': {
    title: 'Billing address',
    isValid: () => !!form.billingAddress,
  },
  'terms': {
    title: 'Terms',
    isValid: () => form.contractAccepted === true,
  },
  'payment': {
    title: 'Payment',
    isValid: () => ['credit-card', 'paypal'].includes(form.payment),
  },
})

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

@innocenzi innocenzi mentioned this pull request Jul 5, 2022
4 tasks
@innocenzi innocenzi changed the title feat(useWizard): new function feat(useStepper): new function Jul 5, 2022
@innocenzi
Copy link
Contributor Author

innocenzi commented Jul 6, 2022

All done, thanks for the review!

'terms',
'payment',
])
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also have a short example of object usage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added it 👍

antfu
antfu previously approved these changes Jul 6, 2022
@antfu antfu merged commit 6b0166e into vueuse:main Jul 6, 2022
@innocenzi innocenzi deleted the feat/use-stepper branch July 6, 2022 18:50
@darrylnoakes
Copy link
Contributor

darrylnoakes commented Jul 6, 2022

Using an object relies on the key order being maintained.
There was almost no spec for this prior to ES2015, and was only properly specced in ES2020.
From an SO answer: "The iteration order for objects follows a certain set of rules since ES2015, but it does not (always) follow the insertion order."

From that second link:

The order for "own" (non-inherited) properties is:

  • Integer-like keys in ascending order
  • String keys in insertion order
  • Symbols in insertion order

Thus, there are three segments, which may alter the insertion order (as happened in the example). And integer-like keys don't stick to the insertion order at all.

In ES2015, only certain methods followed the order:

  • Object.assign
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys
  • JSON.parse
  • JSON.stringify

As of ES2020, all others do (some in specs between ES2015 and ES2020, others in ES2020), which includes:

  • Object.keys, Object.entries, Object.values, ...
  • for..in

I'm not sure if the possibility that this doesn't work in various older/less-major browsers is an issue?

One of the gotchas that could affect this composable is the sorting of different property types.
If this composable is used with a combination of integer keys and non-integer keys, the order will not be maintained.
E.g. "Intro, 1, 2, 3, End" would be changed to "1, 2, 3, Intro, End".
I think this is an actual issue.

A potential fix is to rather pass an array of objects, with each an extra property in each object to specify the name.

@innocenzi
Copy link
Contributor Author

What do you think of disallowing mixed object keys instead, as a compromise? That might prove easier to type.

@darrylnoakes
Copy link
Contributor

Even if it proves easier to type (I doubt it), it is still a compromise, disallowing real use cases.

Any reasons the potential fix I suggested would not work?

@innocenzi
Copy link
Contributor Author

It might work, but I have no clue how to type that, it's more boilerplate and it removes one potential key from the object too.

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

Successfully merging this pull request may close these issues.

None yet

3 participants