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(b-table, b-table-lite): switch slot name syntax to use round brackets instead of square brackets #3986

Merged
merged 14 commits into from Aug 30, 2019
Merged
18 changes: 9 additions & 9 deletions docs/components/componentdoc.vue
Expand Up @@ -50,13 +50,13 @@
bordered
striped
>
<template v-slot:cell[prop]="{ value, item }">
<template v-slot:cell(prop)="{ value, item }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
<b-badge v-if="item.required" variant="info">Required</b-badge>
<b-badge v-else-if="item.deprecated" variant="danger">Deprecated</b-badge>
<b-badge v-else-if="item.deprecation" variant="warning">Deprecation</b-badge>
</template>
<template v-slot:cell[defaultValue]="{ value }">
<template v-slot:cell(defaultValue)="{ value }">
<code v-if="value" class="notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:row-details="{ item }">
Expand All @@ -82,10 +82,10 @@
bordered
striped
>
<template v-slot:cell[prop]="{ value }">
<template v-slot:cell(prop)="{ value }">
<code class="notranslate" translate="no">{{ kebabCase(value) }}</code>
</template>
<template v-slot:cell[event]="{ value }">
<template v-slot:cell(event)="{ value }">
<code class="notranslate" translate="no">{{ value }}</code>
</template>
</b-table>
Expand All @@ -105,7 +105,7 @@
bordered
striped
>
<template v-slot:cell[name]="{ value }">
<template v-slot:cell(name)="{ value }">
<code class="text-nowrap nostranslate" translate="no">{{ value }}</code>
</template>
</b-table>
Expand All @@ -124,10 +124,10 @@
bordered
striped
>
<template v-slot:cell[event]="{ value }">
<template v-slot:cell(event)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[args]="{ value, item }">
<template v-slot:cell(args)="{ value, item }">
<p
v-for="arg in value"
:key="`event-${item.event}-${arg.arg ? arg.arg : 'none'}`"
Expand Down Expand Up @@ -159,10 +159,10 @@
bordered
striped
>
<template v-slot:cell[event]="{ value }">
<template v-slot:cell(event)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[args]="{ value, item }">
<template v-slot:cell(args)="{ value, item }">
<p
v-for="arg in value"
:key="`event-${item.event}-${arg.arg ? arg.arg : 'none'}`"
Expand Down
16 changes: 8 additions & 8 deletions docs/components/importdoc.vue
Expand Up @@ -22,13 +22,13 @@
bordered
striped
>
<template v-slot:cell[component]="{ value }">
<template v-slot:cell(component)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[namedExport]="{ value }">
<template v-slot:cell(namedExport)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[importPath]="{ value }">
<template v-slot:cell(importPath)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
</b-table>
Expand Down Expand Up @@ -57,13 +57,13 @@
bordered
striped
>
<template v-slot:cell[directive]="{ value }">
<template v-slot:cell(directive)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[namedExport]="{ value }">
<template v-slot:cell(namedExport)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[importPath]="{ value }">
<template v-slot:cell(importPath)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
</b-table>
Expand Down Expand Up @@ -97,10 +97,10 @@
bordered
striped
>
<template v-slot:cell[namedExport]="{ value }">
<template v-slot:cell(namedExport)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
<template v-slot:cell[importPath]="{ value }">
<template v-slot:cell(importPath)="{ value }">
<code class="text-nowrap notranslate" translate="no">{{ value }}</code>
</template>
</b-table>
Expand Down
69 changes: 35 additions & 34 deletions src/components/table/README.md
Expand Up @@ -806,9 +806,9 @@ Scoped field slots give you greater control over how the record data appears. Yo
slots to provided custom rendering for a particular field. If you want to add an extra field which
does not exist in the records, just add it to the [`fields`](#fields-column-definitions) array, and
then reference the field(s) in the scoped slot(s). Scoped field slots use the following naming
syntax: `'cell[' + field key + ']'`.
syntax: `'cell(' + field key + ')'`.

You can use the default _fall-back_ scoped slot `'cell[]'` to format any cells that do not have an
You can use the default _fall-back_ scoped slot `'cell()'` to format any cells that do not have an
explicit scoped slot provided.

**Example: Custom data rendering with scoped slots**
Expand All @@ -818,22 +818,22 @@ explicit scoped slot provided.
<div>
<b-table small :fields="fields" :items="items">
<!-- A virtual column -->
<template v-slot:cell[index]="data">
<template v-slot:cell(index)="data">
{{ data.index + 1 }}
</template>

<!-- A custom formatted column -->
<template v-slot:cell[name]="data">
<b>{{ data.value.last }}</b>, {{ data.value.first }}
<template v-slot:cell(name)="data">
<b class="text-info">{{ data.value.last.toUpperCase() }}</b>, <b>{{ data.value.first }}<b>
</template>

<!-- A virtual composite column -->
<template v-slot:cell[nameage]="data">
<template v-slot:cell(nameage)="data">
{{ data.item.name.first }} is {{ data.item.age }} years old
</template>

<!-- Optional default data cell scoped slot -->
<template v-slot:cell[]="data">
<template v-slot:cell()="data">
<i>{{ data.value }}</i>
</template>
</b-table>
Expand Down Expand Up @@ -903,7 +903,7 @@ scoped field slot.
<template>
<div>
<b-table :items="items">
<template v-slot:cell[html]="data">
<template v-slot:cell(html)="data">
<span v-html="data.value"></span>
</template>
</b-table>
Expand Down Expand Up @@ -954,7 +954,7 @@ formatted value as a string (HTML strings are not supported)
<template>
<div>
<b-table :fields="fields" :items="items">
<template v-slot:cell[name]="data">
<template v-slot:cell(name)="data">
<!-- `data.value` is the value after formatted by the Formatter -->
<a :href="`#${data.value.replace(/[^a-z]+/i,'-').toLowerCase()}`">{{ data.value }}</a>
</template>
Expand Down Expand Up @@ -1017,34 +1017,34 @@ It is also possible to provide custom rendering for the tables `thead` and `tfoo
default the table footer is not rendered unless `foot-clone` is set to `true`.

Scoped slots for the header and footer cells uses a special naming convention of
`'head[<fieldkey>]'` and `'foot[<fieldkey>]'` respectively. if a `'foot[...]'` slot for a field is
not provided, but a `'head[...]'` slot is provided, then the footer will use the `'head[...]'` slot
`'head(<fieldkey>)'` and `'foot(<fieldkey>)'` respectively. if a `'foot(...)'` slot for a field is
not provided, but a `'head(...)'` slot is provided, then the footer will use the `'head(...)'` slot
content.

You can use a default _fall-back_ scoped slot `'head[]'` or `'foot[]'` to format any header or
You can use a default _fall-back_ scoped slot `'head()'` or `'foot()'` to format any header or
footer cells that do not have an explicit scoped slot provided.

```html
<template>
<div>
<b-table :fields="fields" :items="items" foot-clone>
<!-- A custom formatted data column cell -->
<template v-slot:cell[name]="data">
<template v-slot:cell(name)="data">
{{ data.value.first }} {{ data.value.last }}
</template>

<!-- A custom formatted header cell for field 'name' -->
<template v-slot:head[name]="data">
<span class="text-info">{{ data.label }}</b>
<template v-slot:head(name)="data">
<span class="text-info">{{ data.label.toUpperCase() }}</b>
</template>

<!-- A custom formatted footer cell for field 'name' -->
<template v-slot:foot[name]="data">
<template v-slot:foot(name)="data">
<span class="text-danger">{{ data.label }}</span>
</template>

<!-- Default fall-back custom formatted footer cell -->
<template v-slot:foot[]="data">
<template v-slot:foot()="data">
<i>{{ data.label }}</i>
</template>
</b-table>
Expand Down Expand Up @@ -1088,7 +1088,7 @@ properties:
| `selectAllRows` | Method | Select all rows (applicable if the table is in [`selectable`](#row-select-support) mode |
| `clearSelected` | Method | Unselect all rows (applicable if the table is in [`selectable`](#row-select-support) mode |

When placing inputs, buttons, selects or links within a `HEAD[...]` or `FOOT[...]` slot, note that
When placing inputs, buttons, selects or links within a `head(...)` or `foot(...)` slot, note that
`head-clicked` event will not be emitted when the input, select, textarea is clicked (unless they
are disabled). `head-clicked` will never be emitted when clicking on links or buttons inside the
scoped slots (even when disabled)
Expand Down Expand Up @@ -1117,7 +1117,7 @@ rather than native browser table child elements.
>
<template v-slot:thead-top="data">
<b-tr>
<b-td colspan="2">&nbsp;</b-td>
<b-th colspan="2"><span class="sr-only">Name and ID</span></b-th>
<b-th variant="secondary">Type 1</b-th>
<b-th variant="primary" colspan="3">Type 2</b-th>
<b-th variant="danger">Type 3</b-th>
Expand Down Expand Up @@ -1250,11 +1250,11 @@ available horizontal space.
- Bootstrap v4 uses the CSS style `border-collapse: collapsed` on table elements. This prevents the
borders on the sticky header from "sticking" to the header, and hence the borders will scroll when
the body scrolls. To get around this issue, create some custom CSS that targets
`table.table.b-table`, which sets they styles `border-collapse: collapsed; border-spacing: 0px;`
`table.table.b-table`, which sets they styles `border-collapse: separate; border-spacing: 0px;`
(note that this may cause double borders when using features such as `bordered`, etc).
- The sticky header feature uses CSS style `position: sticky` to position the headings.
- Internet Explorer does not support `position: sticky`, hence for IE11 the table headings will
scroll with the table body.
- The sticky header feature uses CSS style `position: sticky` to position the headings. Internet
Explorer does not support `position: sticky`, hence for IE11 the table headings will scroll with
the table body.

### Sticky columns

Expand All @@ -1272,10 +1272,10 @@ set.
<b-form-checkbox v-model="stickyHeader" class="mb-2">Sticky header</b-form-checkbox>
<b-table :sticky-header="stickyHeader" responsive :items="items" :fields="fields">
<!-- We are using utility class `text-nowrap` to help illustrate horizontal scrolling -->
<template v-slot:head[id]="scope">
<template v-slot:head(id)="scope">
<div class="text-nowrap">Row ID</div>
</template>
<template v-slot:head[]="scope">
<template v-slot:head()="scope">
<div class="text-nowrap">
Heading {{ scope.label }}
</div>
Expand Down Expand Up @@ -1379,7 +1379,7 @@ initially showing.
<template>
<div>
<b-table :items="items" :fields="fields" striped responsive="sm">
<template v-slot:cell[show_details]="row">
<template v-slot:cell(show_details)="row">
<b-button size="sm" @click="row.toggleDetails" class="mr-2">
{{ row.detailsShowing ? 'Hide' : 'Show'}} Details
</b-button>
Expand Down Expand Up @@ -1486,7 +1486,7 @@ Programmatic selection notes:
responsive="sm"
>
<!-- Example scoped slot for select state illustrative purposes -->
<template v-slot:cell[selected]="{ rowSelected }">
<template v-slot:cell(selected)="{ rowSelected }">
<template v-if="rowSelected">
<span aria-hidden="true">&check;</span>
<span class="sr-only">Selected</span>
Expand Down Expand Up @@ -2652,8 +2652,8 @@ helper components are as follows:

These components are optimized to handle converting variants to the appropriate classes (such as
handling table `dark` mode), and automatically applying certain accessibility attributes (i.e.
`role`s and `scope`s). It can generate the stacked table and sticky-header requirements. Components
`<b-table>` and `<b-table-lite>` use these helper components internally.
`role`s and `scope`s). They also can generate the stacked table, and sticky header and column,
markup. Components `<b-table>` and `<b-table-lite>` use these helper components internally.

In the [Simple tables](#simple-tables) example, we are using the helper components `<b-thead>`,
`<b-tbody>`, `<b-tr>`, `<b-th>`, `<b-tr>` and `<b-tfoot>`. While you can use regular table child
Expand Down Expand Up @@ -2697,9 +2697,10 @@ trigger your click on cells or rows (required for accessibility for keyboard-onl
### Heading accessibility

When a column (field) is sortable (`<b-table>` only) or there is a `head-clicked` listener
registered, the header (and footer) `<th>` cells will be placed into the document tab sequence (via
`tabindex="0"`) for accessibility by keyboard-only and screen reader users, so that the user may
trigger a click (by pressing <kbd>ENTER</kbd> on the header cells.
registered (`<b-table>` and `<b-table-lite>`), the header (and footer) `<th>` cells will be placed
into the document tab sequence (via `tabindex="0"`) for accessibility by keyboard-only and screen
reader users, so that the user may trigger a click (by pressing <kbd>ENTER</kbd> on the header
cells.

### Data row accessibility

Expand Down Expand Up @@ -2881,11 +2882,11 @@ your app handles the various inconsistencies with events.
:sort-direction="sortDirection"
@filtered="onFiltered"
>
<template v-slot:cell[name]="row">
<template v-slot:cell(name)="row">
{{ row.value.first }} {{ row.value.last }}
</template>

<template v-slot:cell[actions]="row">
<template v-slot:cell(actions)="row">
<b-button size="sm" @click="info(row.item, row.index, $event.target)" class="mr-1">
Info modal
</b-button>
Expand Down
4 changes: 3 additions & 1 deletion src/components/table/helpers/mixin-tbody-row.js
Expand Up @@ -203,7 +203,9 @@ export default {
// The new `v-slot` syntax doesn't like a slot name starting with
// a square bracket and if using in-document HTML templates, the
// v-slot attributes are lower-cased by the browser.
const slotNames = [`cell[${key}]`, `cell[${key.toLowerCase()}]`, 'cell[]']
// Switched to round bracket syntax to prevent confusion with
// dynamic slot name syntax.
const slotNames = [`cell(${key})`, `cell(${key.toLowerCase()})`, 'cell()']
let $childNodes = this.hasNormalizedSlot(slotNames)
? this.normalizeSlot(slotNames, slotScope)
: toString(formatted)
Expand Down
10 changes: 6 additions & 4 deletions src/components/table/helpers/mixin-thead.js
Expand Up @@ -106,13 +106,15 @@ export default {
// Handle edge case where in-document templates are used with new
// `v-slot:name` syntax where the browser lower-cases the v-slot's
// name (attributes become lower cased when parsed by the browser)
let slotNames = [`head[${field.key}]`, `head[${field.key.toLowerCase()}]`, 'head[]']
// We have replaced the square bracket syntax with round brackets
// to prevent confusion with dynamic slot names
let slotNames = [`head(${field.key})`, `head(${field.key.toLowerCase()})`, 'head()']
if (isFoot) {
// Footer will fallback to header slot names
slotNames = [
`foot[${field.key}]`,
`foot[${field.key.toLowerCase()}]`,
'foot[]',
`foot(${field.key})`,
`foot(${field.key.toLowerCase()})`,
'foot()',
...slotNames
]
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/table/table-row-details.spec.js
Expand Up @@ -187,7 +187,7 @@ describe('table > row details', () => {
scopeDetails = scope
return 'foobar'
},
'cell[a]': function(scope) {
'cell(a)': function(scope) {
scopeField = scope
return 'AAA'
}
Expand Down
12 changes: 6 additions & 6 deletions src/components/table/table-tbody-row-events.spec.js
Expand Up @@ -333,13 +333,13 @@ describe('table > tbody row events', () => {
},
slots: {
// In Vue 2.6x, slots get translated into scopedSlots
'cell[a]': '<button id="a">button</button>',
'cell[b]': '<input id="b">',
'cell[c]': '<a href="#" id="c">link</a>',
'cell[d]':
'cell(a)': '<button id="a">button</button>',
'cell(b)': '<input id="b">',
'cell(c)': '<a href="#" id="c">link</a>',
'cell(d)':
'<div class="dropdown-menu"><div id="d" class="dropdown-item">dropdown</div></div>',
'cell[e]': '<label for="e">label</label><input id="e">',
'cell[f]': '<label class="f-label"><input id="e"></label>'
'cell(e)': '<label for="e">label</label><input id="e">',
'cell(f)': '<label class="f-label"><input id="e"></label>'
},
listeners: {
// Row-clicked will only occur if there is a registered listener
Expand Down
6 changes: 3 additions & 3 deletions src/components/table/table-tfoot-events.spec.js
Expand Up @@ -106,10 +106,10 @@ describe('table > tfoot events', () => {
},
slots: {
// In Vue 2.6x, slots get translated into scopedSlots
'foot[a]': '<button id="a">button</button>',
'foot[b]': '<input id="b">',
'foot(a)': '<button id="a">button</button>',
'foot(b)': '<input id="b">',
// Will use `head` slot if foot slot not defined
'head[c]': '<a href="#" id="c">link</a>'
'head(c)': '<a href="#" id="c">link</a>'
}
})
expect(wrapper).toBeDefined()
Expand Down