diff --git a/packages/nimble-components/src/table/specs/table-column-specs/table-column-anchor-hld.md b/packages/nimble-components/src/table/specs/table-column-specs/table-column-anchor-hld.md index 7b270e0126..351ac0443c 100644 --- a/packages/nimble-components/src/table/specs/table-column-specs/table-column-anchor-hld.md +++ b/packages/nimble-components/src/table/specs/table-column-specs/table-column-anchor-hld.md @@ -68,10 +68,6 @@ When grouped, the header item should not be a link. The column will also support having a custom sort order, as detailed in the [Custom Sort Order HLD](../table-column-custom-sort-field-hld.md). -### Clearing state - -Because the anchor in the cell can have focus, we must override `focusedRecycleCallback()` in our cell view and have it call `blur()` on our anchor. If we don't, the focus can pass to other cells as you scroll. - ### Sizing The column should support the same sizing modes as the text column, which is fractional widths plus minimum pixel widths. @@ -84,9 +80,9 @@ Arrowing to a anchor table cell should focus the link (if it is actually a link In the accessibility tree, the cells of an anchor column are instances of [`nimble-table-cell`](https://github.com/ni/nimble/blob/f663c38741e731bef91aa58e8fb2d1cec653b679/packages/nimble-components/src/table/components/cell/template.ts#L6) which has a `role` of [`cell`](https://w3c.github.io/aria/#cell). The cell then has a child `nimble-anchor`, which has a `role` of [`link`](https://w3c.github.io/aria/#link). -### Angular RouterLink Support +### Angular Routing support -The real challenge of this column type is integrating with the Angular router. The `RouterLink`/`RouterLinkWithHref` directives are used to intercept clicks on anchors and replace the default navigation action with a call to `Router.navigateByUrl()`. As we have done in the past for other anchor components, we will have our own directive deriving from `RouterLinkWithHref`. Our directive will apply based on the presence of the `nimbleRouterLink` attribute. As we have done in the past, we will also have a directive that throws an error if `routerLink` is used instead. Normally, you would specify the `nimbleRouterLink` and related attributes (e.g. `queryParams`, `replaceUrl`, etc.) directly on the anchor element, but that's not possible for anchors in generated table cells. Our options are to put the directive on `nimble-table` or `nimble-table-column-anchor`. Because we would like to allow different anchor columns to be configured differently, and because it is a more intuitive API, we want to put our directive on the column element: +Using the `TableColumnAnchor` in Angular requires the use of the [`NavigationGuard`](https://github.com/ni/nimble/blob/main/packages/angular-workspace/nimble-angular/table-column/anchor/nimble-table-column-anchor-navigation-guard.directive.ts) in order to allow proper routing within the Angular application. ```html diff --git a/packages/nimble-components/src/table/specs/table-column-specs/table-column-mapping-anchor.md b/packages/nimble-components/src/table/specs/table-column-specs/table-column-mapping-anchor.md new file mode 100644 index 0000000000..ab86af9e06 --- /dev/null +++ b/packages/nimble-components/src/table/specs/table-column-specs/table-column-mapping-anchor.md @@ -0,0 +1,197 @@ +# Mapping Anchor Table Column + +## Overview + +The `nimble-table-column-mapping-anchor` is a component that supports rendering specific number, boolean, or string values as an icon or a spinner, with an accompanying text anchor element. The mappings are defined by child elements of `nimble-mapping-icon`, `nimble-mapping-spinner`, or `nimble-mapping-empty`. + +### Background + +[Icon with anchor column](https://github.com/ni/nimble/issues/2531) + +### Features + +- Supported input: + - string + - number + - boolean +- Supported output: + - Icon with text link + - Spinner with text link + - text link + +### Non-goals + +- Non-Nimble icon support +- Arbitrary icon colors +- Non-icon, non-spinner Nimble components +- Specifying different text for an icon/spinner's label than the overall text of the mapping + +--- + +## Design + +Below is an example of how these elements would be used within a `nimble-table`: + +```HTML + + + Status + + + + + + +``` + +The notable distinction between this column type and the `nimble-table-column-mapping` is the `label-field-name` and `href-field-name` attributes, and the absence of supporting the `nimble-mapping-text` as one of its mapping types. The two new attributes are aligned with the `nimble-table-column-anchor` API, and provide the fields in the table record for the text and URL for the displayed link. The `nimble-mapping-text` mapping will not be supported as it seems unnecessary for the use-cases needed. + +See the [Mapping Table Column spec](./table-column-mapping.md#design), and the [Anchor Table Column spec](./table-column-anchor-hld.md#implementation--design) for more details related to the design. + +### API + +#### Enum column element: + +_Component Name_ + +- `nimble-table-column-mapping-anchor` + +_Props/Attrs_ + +##### Attributes inherited from TableColumnEnumBase + +- `field-name`: string +- `key-type`: 'string' | 'number' | 'boolean' + +##### Attributes "copied" from TableColumnAnchor (intend to move to mixin) + +- `label-field-name`: string +- `href-field-name`: string +- `appearance`: string +- `underline-hidden`: string +- `hreflang` +- `ping` +- `referrerpolicy` +- `rel` +- `target` +- `type` +- `download` + +Attributes from [`FractionalWidth`](https://github.com/ni/nimble/blob/main/packages/nimble-components/src/table-column/mixins/fractional-width-column.ts), [`GroupableColumn`](https://github.com/ni/nimble/blob/main/packages/nimble-components/src/table-column/mixins/groupable-column.ts), and [`Placeholder`](https://github.com/ni/nimble/blob/main/packages/nimble-components/src/table-column/mixins/placeholder.ts) mixins. + +_Content_ + +- column title (icon and/or text) +- 1 or more `nimble-mapping-icon`, `nimble-mapping-spinner`, or `nimble-mapping-empty` elements + +### Cell Template + +The cell template will essentially be a combination of the `TableColumnMappingCellView` and `TableColumnAnchorCellView`. + +```html + ${x => x.visualizationTemplate} +When cellRecord.href present + + ${cellState.cellRecord.label ?? cellState.cellRecord.href} + +When cellRecord.href is missing + + ${cellState.cellRecord.label} + +``` + +### Sorting + +Sorting will be based on the record value, following what is described in the [Mapping Table Column spec](./table-column-mapping.md#sorting), meaning the column will ultimately be sorted according to the icon "value" and not by the label or URL (as it is with the anchor column). + +### Sizing + +The column should support the same sizing modes as the text column, which is fractional widths plus minimum pixel widths. + +### Keyboard Interactions + +Arrowing to a anchor table cell should focus the link (if it is actually a link and not just a text span). Pressing `Enter` on a focused link will trigger navigation. + +### Accessibility Roles + +In the accessibility tree, the cells of an anchor column are instances of [`nimble-table-cell`](https://github.com/ni/nimble/blob/f663c38741e731bef91aa58e8fb2d1cec653b679/packages/nimble-components/src/table/components/cell/template.ts#L6) which has a `role` of [`cell`](https://w3c.github.io/aria/#cell). The cell then has a child `nimble-anchor`, which has a `role` of [`link`](https://w3c.github.io/aria/#link). + +### Angular integration + +Angular directives will be created for the column component. No component has form association, so a `ControlValueAccessor` will not be created. + +#### Angular Routing support + +Using the `TableColumnAnchor` in Angular requires the use of the [`NavigationGuard`](https://github.com/ni/nimble/blob/main/packages/angular-workspace/nimble-angular/table-column/anchor/nimble-table-column-anchor-navigation-guard.directive.ts) in order to allow proper routing within the Angular application. + +### Blazor integration + +Blazor wrappers will be created for the components. Columns will be generic in the type of the key, and will cascade that type parameter to contained mapping elements (see [`CascadingTypeParameter`](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/generic-type-support?view=aspnetcore-7.0#cascaded-generic-type-support)): + +```HTML + + + + + + +``` + +### Globalization + +All text will be provided by the client and is expected to be localized. + +### Security + +N/A + +### Performance + +N/A + +### 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 + - validation error when non-unique mapping keys exist + - validation error when invalid icon name given + - grouping header for icon column includes text +- Verify manually that the column content appears in the accessibility tree and can be read by a screen reader. +- Verify manually that several mapping columns with thousands of elements scrolls performantly. +- Visual Chromatic tests will be created + +### Tooling + +N/A + +### Documentation + +Documented in Storybook + +--- + +## Open Issues