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

Mapping table column spec #1220

Merged
merged 31 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1ddda56
Initial spec
m-akinc May 1, 2023
afc2dda
Link from main table spec
m-akinc May 1, 2023
8a2c5a9
Updates
m-akinc May 1, 2023
5149672
Update
m-akinc May 1, 2023
dffcc0a
Updates
m-akinc May 1, 2023
1c7876a
Add code for ellipsized text tooltip
m-akinc May 1, 2023
d72e90b
Updates
m-akinc May 2, 2023
b5b80ea
some feedback
m-akinc May 3, 2023
2af533d
Big revamp
m-akinc May 4, 2023
9e9061f
Change files
m-akinc May 4, 2023
a00ff8e
Address most of Molly's feedback
m-akinc May 4, 2023
fa90d2a
Address some feedback
m-akinc May 5, 2023
28582a6
not throwing errors
m-akinc May 5, 2023
f813463
Expand on sorting
m-akinc May 5, 2023
40ebb7a
Fixes
m-akinc May 5, 2023
eaf9b00
Split key property into multiple type-specific props
m-akinc May 8, 2023
3195be9
Add column validation section to columns HLD
m-akinc May 8, 2023
6bbf1df
Updates
m-akinc May 8, 2023
a0ad5bd
Updates
m-akinc May 15, 2023
9047098
Rename default property to default-mapping
m-akinc May 15, 2023
ebd2ff3
Update column validation documentation
m-akinc May 19, 2023
986aefb
Updates
m-akinc May 19, 2023
57448bb
Update validation documentation
m-akinc May 19, 2023
7e27c21
Update sorting section
m-akinc May 23, 2023
4cbd0bb
Update packages/nimble-components/src/table/specs/table-column-specs/…
m-akinc May 24, 2023
9a39440
Merge branch 'users/makinc/icon-column-spec' of https://github.com/ni…
m-akinc May 24, 2023
643cd8f
Clearly lay out sort options
m-akinc May 24, 2023
c81af5b
Update
m-akinc May 24, 2023
6ba69f5
Update packages/nimble-components/src/table/specs/table-column-specs/…
m-akinc May 30, 2023
9977915
Update packages/nimble-components/src/table/specs/table-column-specs/…
m-akinc May 30, 2023
74cee98
Merge branch 'main' into users/makinc/icon-column-spec
m-akinc May 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/nimble-components/src/table/specs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ The various APIs/features of the `nimble-table` will be split up amongst several
- List the set of column providers that Nimble will provide and provide their respective APIs where unique (e.g., formatter for DateTime column)
- [TableColumnText](table-column-specs/table-column-text-field.md)
- [TableColumnAnchor](table-column-specs/table-column-anchor-hld.md)
- [TableColumnMapping](table-column-specs/table-column-mapping.md)
- Headers
- Define the anatomy of headers in the table DOM
- What is the component to use for interaction? Outline Button? Ghost button?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
# Mapping Table Column

## Overview

The `nimble-table-column-mapping` is a component that supports rendering specific number, boolean, or string values as mapped icons, spinners, or text. `nimble-table-column-icon` is a specialized version of `nimble-table-column-mapping` which defaults to having a minimal, fixed width. The actual mappings are defined by child elements `nimble-mapping-icon`, `nimble-mapping-spinner`, and `nimble-mapping-text`.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

### Background

[Icon column type issue](https://github.com/ni/nimble/issues/1013)

[Boolean column type issue](https://github.com/ni/nimble/issues/1103)

### Features

- Supported input:
- string
- number
- boolean
- Supported output:
- Text
- Icon
- Spinner
- (empty)

### Non-goals

- Non-Nimble icon support
- Arbitrary icon colors
- Hyperlink icons
- Mixed text and icons
- Non-icon, non-spinner Nimble components

---

## Design

Below is an example of how these elements would be used within a `nimble-table`:

```HTML
<nimble-table>
<nimble-table-column-icon field-name="status">
Status
<nimble-mapping-icon key="fail" icon="nimble-icon-xmark" severity="error" label="Failed"></nimble-mapping-icon>
<nimble-mapping-icon key="error" icon="nimble-icon-xmark" severity="error" label="Errored"></nimble-mapping-icon>
<nimble-mapping-icon key="pass" icon="nimble-icon-check" severity="success" label="Passed"></nimble-mapping-icon>
<nimble-mapping-spinner key="running" label="Running..."></nimble-mapping-spinner>
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
</nimble-table-column-icon>
<nimble-table-column-mapping field-name="errorCode" data-type="number">
Error Code
<nimble-mapping-text key="1" label="A bad thing happened"></nimble-mapping-text>
<nimble-mapping-text key="2" label="A worse thing happened"></nimble-mapping-text>
<nimble-mapping-text key="3" label="A terrible thing happened"></nimble-mapping-text>
</nimble-table-column-mapping>
<nimble-table-column-icon field-name="archived" data-type="boolean">
Archived
<nimble-mapping-icon key="true" icon="nimble-icon-database" label="Archived"></nimble-mapping-icon>
</nimble-table-column-icon>
</nimble-table>
```

Note that the `key` attribute values are always given as strings. In the case of boolean or number mappings, this value is parsed to the appropriate type, so that it can properly be compared to the values from the row records.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

When none of the given mappings match the record value for a cell, that cell will be empty. Alternatively, we could provide support for marking a mapping with a `default` attribute that would cause it to be chosen when no other values matched. This would be equivalent to the `placeholder` configuration we provide on `nimble-table-column-text` and `nimble-table-column-anchor`. I don't think we need to support this initially.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

If multiple mappings in a column have the same key, an error will be thrown.

If an invalid `icon` value is passed to `nimble-mapping-icon`, an error will be thrown.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

`nimble-table-column-icon` supports only `nimble-mapping-icon` and `nimble-mapping-spinner` as mapping elements. Any others will result in an error being thrown. `nimble-table-column-mapping` supports all mapping elements.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

Text in a grouping header or in the cell will be ellipsized and gain a tooltip when the full text is too long to display.

**Alternatives:**
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

An earlier version of this spec proposed mapping elements with `template` elements as content instead of relying on attribute configuration. The template element would define the mapped html to render. We would impose restrictions on the types of supported elements that could be provided in the template.

Pros:

- It would not require updates to the API if we needed to support new types of mapped content (e.g. icon with text), or if the mapped content itself got new configuration options (e.g. a scaling factor for icons).
- Undefined element types caught at compile time.

Cons:

- Verbose. Requires user to create `template` element and wrap text in `span`s for styling purposes.
- Requires difficult validation to ensure only supported elements are present in the `template`.
- Could allow users to provide inline styling.
- Blazor: cannot put Blazor components inside `template`--must use raw Nimble elements without type safety

### API

#### Icon column element:

_Component Name_

- `nimble-table-column-icon`

_Props/Attrs_

- `field-name`: string
- `data-type`: 'string' | 'boolean' | 'number' (defaults to 'string')
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
- `pixel-width`: number (defaults to minimum width supported by table)
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

_Content_

- column title (text)
rajsite marked this conversation as resolved.
Show resolved Hide resolved
- 1 or more `nimble-mapping-icon` or `nimble-mapping-spinner` elements

#### General mapping column element:

_Component Name_

- `nimble-table-column-mapping`

_Props/Attrs_

- `field-name`: string
- `data-type`: 'string' | 'boolean' | 'number' (defaults to 'string')
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
- `pixel-width`: number (set to the desired fixed column width, else will have a fractional width)
rajsite marked this conversation as resolved.
Show resolved Hide resolved
- `fractional-width`: number (defaults to 1)
- `min-pixel-width`: number (defaults to minimum supported by table)

_Content_

- column title (text)
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
- 1 or more `nimble-mapping-*` elements
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

#### Mapping element (icon):

_Component Name_

- `nimble-mapping-icon`

_Props/Attrs_

- `key`: string (will also have a private, typed version of this property)
- `icon`: string - name of the Nimble icon element
- `severity`: string - one of the supported enum values. Controls color of the icon.
- `label`: string - localized value used as the accessible name and `title` of the icon
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

#### Mapping element (spinner):

_Component Name_

- `nimble-mapping-spinner`

_Props/Attrs_

- `key`: string (will also have a private, typed version of this property)
- `label`: string - localized value used as the accessible name and `title` of the spinner
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

#### Mapping element (text):

_Component Name_

- `nimble-mapping-spinner`

_Props/Attrs_

- `key`: string (will also have a private, typed version of this property)
- `label`: string - display text

### Anatomy

#### `nimble-table-column-mapping`
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

```HTML
<template slot="${x => x.columnInternals.uniqueId}">
<slot
${slotted('mappings')}
name="mapping">
</slot>
<span class="header-content">
<slot></slot>
</span>
</template>
```

Cell view:

The cell view relies on the matched mapping to provide a template to render.

```HTML
${repeat(x => (x.column as TableColumnMapping).mappings,
html<TableColumnMapping, TableColumnMappingCellView>`
${when((x, c) => x.typedKey === (c.parent as TableColumnMappingCellView).cellRecord.value,
html<TableColumnMapping>`${x => x.cellViewTemplate}`
)}
`
)}
```

Group header view:

Similarly, the group header view relies on the matched mapping to provide a template to render.

Note the following requires that `TableColumnMappingGroupHeaderView` has a reference to the column with which it is associated. This is needed to enumerate the column's mapping elements.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

```HTML
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
${repeat(x => (x.column as TableColumnMapping).mappings,
html<TableColumnMapping, TableColumnMappingHeaderView>`
${when((x, c) => x.key === (c.parent as TableColumnMappingHeaderView).groupHeaderValue,
html<TableColumnMapping>`${x => x.groupHeaderViewTemplate}`
)}
`
)}
```

#### `nimble-mapping-*`

```HTML
<template slot="mapping"></template>
```

#### `nimble-mapping-icon`

Cell view template:

```
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

```

### Grouping

Will support grouping by the record value. The grouping header will display the rendered icon/spinner/text. In the case of an icon/spinner, it will also be followed by the `label` text. This will disambiguate cases where multiple record values map to the same icon (assuming the labels are different). Text in a grouping header will be ellipsized and gain a tooltip if there is not enough room to display it all.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

### Sorting

Sorting will be based on the record value. For icons, if multiple values map the to same icon, it is possible that sorting will result in the instances of a certain icon not being all together in one span of rows. The user may think they should be all together, but this is a corner case that we can't/shouldn't do anything about.
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

### Sizing

`nimble-table-column-icon` will support only a fixed width. We will introduce a new mixin for fixed-width support that exposes a `pixel-width` property. The default value will be the minimum supported by the table, which is still significantly larger than the width of an icon.

`nimble-table-column-mapping` will support fixed or fractional widths. If `pixel-width` is set, the column will have a fixed width, otherwise it defaults to a fractional width of 1. The client may configure `fractional-width` and/or `min-pixel-width`.

### Angular integration

Angular directives will be created for the column components and the mapping components. No component has form association, so a `ControlValueAccessor` will not be created.

### Blazor integration

Blazor wrappers will be created for the components.

### Visual Appearance

The cell view (and group header view) will be responsible for styling the templates returned by the mappings. This will include alignment and spacing (`--ni-nimble-small-padding`). Unfortunately, because the mappings cannot provide CSS to go with the templates they return, some implementation knowledge will leak from the mappings to the cell/group header views. For example, we must set `flex-shrink: 0` on all elements so that icons do not get smaller in a group header when the adjacent label takes up all the space.
rajsite marked this conversation as resolved.
Show resolved Hide resolved
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

---

## Implementation

### States

N/A

### Accessibility

Text, icons, and spinner are not interactive and cannot receive keyboard focus. These items already have proper accessibility roles, and we will set accessible names (`aria-label`) based on the `label` value provided by the client.

### Globalization

All text will be provided by the client and is expected to be localized.

### Security

N/A

### Performance

N/A
m-akinc marked this conversation as resolved.
Show resolved Hide resolved

### Dependencies

None

### Test Plan

- Unit tests will be written verifying the usual component expectations, plus:
- renders mapping matching the cell value (string, number, and boolean)
- nothing rendered when value matches no mappings
- error thrown when non-unique mapping keys exist
- error thrown when non-parsable value is given to number/boolean mappings
- error thrown when invalid icon name given
- error thrown when icon column has a `nimble-mapping-text` element
- grouping header for icon column includes label
- Verify manually that the column content appears in the accessibility tree and can be read by a screen reader.
- Visual Chromatic tests will be created

### Tooling

N/A

### Documentation

Documented in Storybook

---

## Open Issues
m-akinc marked this conversation as resolved.
Show resolved Hide resolved