Skip to content

Commit

Permalink
feat(docs): Update QBtn/QBreadcrumbs/QItem/QRouteTab pages for the up…
Browse files Browse the repository at this point in the history
…dated router-link specs
  • Loading branch information
rstoenescu committed Oct 2, 2022
1 parent 6603aa2 commit 60d0ddf
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 28 deletions.
43 changes: 43 additions & 0 deletions docs/src/examples/QBreadcrumbs/LinksWithGo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<template>
<div class="q-pa-md q-gutter-sm">
<q-breadcrumbs>
<q-breadcrumbs-el label="Delayed" icon="widgets" to="/" @click="onDelayedClick" />
<q-breadcrumbs-el label="Cancelled" icon="navigation" to="/" @click="onCancelledClick" />
<q-breadcrumbs-el label="Redirected" icon="build" to="/" @click="onRedirectedClick" />
<q-breadcrumbs-el label="Page" />
</q-breadcrumbs>
</div>
</template>

<script>
export default {
methods: {
onDelayedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// console.log('triggering navigation in 2s')
setTimeout(() => {
// console.log('navigating as promised 2s ago')
go()
}, 2000)
},
onCancelledClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// then we never call go()
},
onRedirectedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// call this at your convenience
go({
to: '/start/pick-quasar-flavour' // we pick another route
// replace: boolean; default is what the tab is configured with
// returnRouterError: boolean
}).then(_vueRouterResult => { /* ... */ })
.catch(_err => { /* ...we have a vue router error... */ })
}
}
}
</script>
40 changes: 40 additions & 0 deletions docs/src/examples/QBtn/LinksWithGo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="q-pa-md q-gutter-sm">
<q-btn to="/" label="Delayed navigation" @click="onDelayedClick" outline color="purple" no-caps />
<q-btn to="/" label="Cancelled navigation" @click="onCancelledClick" glossy color="purple" no-caps />
<q-btn to="/" label="Redirected navigation" @click="onRedirectedClick" glossy color="purple" no-caps />
</div>
</template>

<script>
export default {
methods: {
onDelayedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// console.log('triggering navigation in 2s')
setTimeout(() => {
// console.log('navigating as promised 2s ago')
go()
}, 2000)
},
onCancelledClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// then we never call go()
},
onRedirectedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// call this at your convenience
go({
to: '/start/pick-quasar-flavour' // we pick another route
// replace: boolean; default is what the tab is configured with
// returnRouterError: boolean
}).then(_vueRouterResult => { /* ... */ })
.catch(_err => { /* ...we have a vue router error... */ })
}
}
}
</script>
48 changes: 48 additions & 0 deletions docs/src/examples/QItem/LinksWithGo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<div class="q-pa-md q-gutter-sm">
<q-item to="/" @click="onDelayedClick" dense>
<q-item-section>Delayed navigation</q-item-section>
</q-item>

<q-item to="/" @click="onCancelledClick" dense>
<q-item-section>Cancelled navigation</q-item-section>
</q-item>

<q-item to="/" @click="onRedirectedClick" dense>
<q-item-section>Redirected navigation</q-item-section>
</q-item>
</div>
</template>

<script>
export default {
methods: {
onDelayedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// console.log('triggering navigation in 2s')
setTimeout(() => {
// console.log('navigating as promised 2s ago')
go()
}, 2000)
},
onCancelledClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// then we never call go()
},
onRedirectedClick (e, go) {
e.preventDefault() // mandatory; we choose when we navigate
// call this at your convenience
go({
to: '/start/pick-quasar-flavour' // we pick another route
// replace: boolean; default is what the tab is configured with
// returnRouterError: boolean
}).then(_vueRouterResult => { /* ... */ })
.catch(_err => { /* ...we have a vue router error... */ })
}
}
}
</script>
17 changes: 14 additions & 3 deletions docs/src/pages/vue-components/breadcrumbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,27 @@ The QBreadcrumbs component is used as a navigational aid in UI. It allows users
<doc-api file="QBreadcrumbsEl" />

## Usage

### Basic

<doc-example title="Basic" file="QBreadcrumbs/Basic" />

<doc-example title="In a QToolbar" file="QBreadcrumbs/Toolbar" />

### Design

<doc-example title="Custom separators" file="QBreadcrumbs/Separator" />

The example below won't work with UMD version (so in Codepen/jsFiddle too) because it depends on Vue Router.
<doc-example title="Gutters" file="QBreadcrumbs/Gutters" />

<doc-example title="Align" file="QBreadcrumbs/Align" />

### Connecting with Vue Router

The examples below won't work with UMD version (so in Codepen/jsFiddle too) because they depend on Vue Router.

<doc-example title="Router links" file="QBreadcrumbs/RouterLinks" />

<doc-example title="Gutters" file="QBreadcrumbs/Gutters" />
You can also delay, cancel or redirect navigation, as seen below. For a more in-depth description of the `@click` event being used below, please refer to QBreadcrumbsEl API card at the top of the page.

<doc-example title="Align" file="QBreadcrumbs/Align" />
<doc-example title="Links with delayed, cancelled or redirected navigation (v1.21+)" file="QBreadcrumbs/LinksWithGo" no-edit />
6 changes: 5 additions & 1 deletion docs/src/pages/vue-components/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Should you wish, you can also display a deterministic progress within the button

<doc-example title="Custom ripple" file="QBtn/CustomRipple" />

### Handling navigation <q-badge align="top" color="brand-primary" label="updated for v1.17+" />
### Connecting to Vue Router <q-badge align="top" color="brand-primary" label="updated for v1.21+" />

::: warning UMD usage
* If you will be using `to` & `replace` props, make sure that you also inject Vue Router in your project. Otherwise use the alternative `href` prop.
Expand All @@ -84,6 +84,10 @@ Prefer the Vue Router props over `href` when you can, because with `href` you wi

<doc-example title="Links" file="QBtn/Links" no-edit />

You can also delay, cancel or redirect navigation, as seen below. For a more in-depth description of the `@click` event being used below, please refer to QBtn API card at the top of the page.

<doc-example title="Links with delayed, cancelled or redirected navigation (v1.21+)" file="QBtn/LinksWithGo" no-edit />

For more convoluted use-cases, you can also directly use the native Vue `<router-link>` component to wrap a QBtn. This also gives the opportunity to control the state according to app's current route:

<doc-example title="Scoped slot of RouterLink" file="QBtn/RouterLink" no-edit />
Expand Down
4 changes: 4 additions & 0 deletions docs/src/pages/vue-components/list-and-list-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@ You can use QItems together with Vue Router through `<router-link>` properties b
</q-item-section>
</q-item>
```

You can also delay, cancel or redirect navigation, as seen below. For a more in-depth description of the `@click` event being used below, please refer to QItem API card at the top of the page.

<doc-example title="Links with delayed, cancelled or redirected navigation (v1.21+)" file="QItem/LinksWithGo" no-edit />
61 changes: 42 additions & 19 deletions docs/src/pages/vue-components/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ QTabPanels can be used as standalone too. They do not depend on the presence of
More info: [Tab Panels](/vue-components/tab-panels).

## Connecting to Vue Router

You can use tabs together with Vue Router through `QRouteTab` component.
This component inherits everything from QTab, however it also has `router-link` properties bound to it. These allow for listening to the current app route and also triggering a route when clicked/tapped.

Expand All @@ -131,33 +132,48 @@ This component inherits everything from QTab, however it also has `router-link`
```

::: warning
QRouteTab becomes "active" depending on your app's route and not due to the v-model. So the initial value of v-model or changing the v-model directly will not also change the route of your app.
When using QTabs with QRouteTab, it is not recommended to also use a v-model (though you still can), because the source of truth for the current active tab is determined by the current route instead of the v-model. Each QRouteTab becomes "active" depending on your app's route and not due to the v-model. So the initial value of v-model or changing the v-model directly will not also change the route of your app.
:::

### Matching QRouteTab to current route <q-badge align="top" color="brand-primary" label="updated for v1.21+" />

* If it is set to `exact` matching:
1. The route that it points to must be considered "exact-active" by Vue Router (exactly matches route, hash & query).
2. Is it pointing to a route that does NOT get redirected to another one? Then it wins.
3. Otherwise, we keep on looking only for other "exact-active" matching QRouteTabs. Maybe we'll find one that does NOT redirect.
* Else, if it is NOT set to `exact` matching:
1. The route that it points to must be considered "active" by Vue Router (loosely matches route, hash & query).
2. If there are still multiple QRouteTabs matching the criteria above, then the ones NOT pointing to a route that gets redirected win.
3. If multiple QRouteTab still match the current route (ex: route is /cars/brands/tesla and we have QRouteTabs pointing to non-exact /cars, non-exact /cars/brands, non-exact /cars/brands/tesla), then the most specific one that matches current route wins (in this case /cars/brands/tesla)
4. If there are still multiple QRouteTabs matching the criteria above, then the one with the query that is closest to the current route query wins (has the configured query and the current route query has the least number of extra params).
5. If there are still multiple QRouteTabs matching the criteria above, then the one with the resulting href that is the lengthier one wins.

The `exact` configured QRouteTabs always win over loose-matching (non-exact) ones.

### Handling custom navigation

::: tip
Please refer to the QRouteTab API card at the top of the page for a more in-depth description of the `@click` event being used below.
:::

```html
<template>
<div class="q-pa-md">
<div class="q-gutter-y-md" style="max-width: 600px">
<q-tabs
no-caps
class="bg-orange text-white shadow-2"
>
<q-route-tab :to="{ query: { tab: '1' } }" exact replace label="Activate in 2s" @click="navDelay" />
<q-route-tab :to="{ query: { tab: '2' } }" exact replace label="Do nothing" @click="navCancel" />
<q-route-tab :to="{ query: { tab: '3' } }" exact replace label="Navigate to the second tab" @click="navRedirect" />
<q-route-tab :to="{ query: { tab: '4' } }" exact replace label="Navigate immediatelly" @click="navPass" />
</q-tabs>
</div>
</div>
<q-tabs
no-caps
class="bg-orange text-white shadow-2"
>
<q-route-tab :to="{ query: { tab: '1' } }" exact replace label="Activate in 2s" @click="navDelay" />
<q-route-tab :to="{ query: { tab: '2' } }" exact replace label="Do nothing" @click="navCancel" />
<q-route-tab :to="{ query: { tab: '3' } }" exact replace label="Navigate to the second tab" @click="navRedirect" />
<q-route-tab :to="{ query: { tab: '4' } }" exact replace label="Navigate immediately" @click="navPass" />
</q-tabs>
</template>

<script>
export default {
methods: {
navDelay (e, go) {
e.navigate = false // we cancel the default navigation
e.preventDefault() // we cancel the default navigation
// console.log('triggering navigation in 2s')
setTimeout(() => {
Expand All @@ -167,13 +183,20 @@ export default {
},
navCancel (e) {
e.navigate = false // we cancel the default navigation
e.preventDefault() // we cancel the default navigation
},
navRedirect (e, go) {
e.navigate = false // we cancel the default navigation
go({ query: { tab: '2', noScroll: true } })
e.preventDefault() // we cancel the default navigation
// call this at your convenience
go({
to: { query: { tab: '2', noScroll: true } },
// replace: boolean; default is what the tab is configured with
// returnRouterError: boolean
})
.then(vueRouterResult => { /* ... */ })
.catch(err => { /* ...we have a vue router error... */ })
},
navPass () {}
Expand Down
9 changes: 4 additions & 5 deletions ui/src/components/tabs/QTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,6 @@ export default Vue.extend({
return done
},

__hasActiveNonRouteTab () {
return this.tabVmList.some(tab => tab.hasRouterLink === void 0 && tab.name === this.currentModel)
},

// do not use directly; use __verifyRouteModel() instead
__updateActiveRoute () {
let name = null, bestScore = getDefaultBestScore()
Expand Down Expand Up @@ -541,7 +537,10 @@ export default Vue.extend({
}
}

if (name === null && this.__hasActiveNonRouteTab() === true) {
if (
name === null &&
this.tabVmList.some(tab => tab.hasRouterLink === void 0 && tab.name === this.currentModel) === true
) {
// we shouldn't interfere if non-route tab is active
return
}
Expand Down

0 comments on commit 60d0ddf

Please sign in to comment.