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

Remove remaining deprecated apis #12

Merged
merged 11 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@

* `cd docs-app`
* `pnpm start` – starts the test app and tests are available at `/tests`

## Notes, Caveats, and Bugs

Until [this pnpm issue#4965](https://github.com/pnpm/pnpm/issues/4965) is fixed,
with the peer-dependency requirements of this repo, every time you re-build the addon,
you'll need to re-run `pnpm install` to re-create the links in the local `node_modules/.pnpm` store.
Thankfully, this is pretty fast.
2 changes: 1 addition & 1 deletion docs-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"edition": "octane"
},
"dependencies": {
"@crowdstrike/ember-oss-docs": "^1.0.29",
"@crowdstrike/ember-oss-docs": "^1.1.0",
"@ember/test-waiters": "^3.0.2",
"@embroider/router": "^1.9.0",
"dompurify": "^2.4.0",
Expand Down
12 changes: 12 additions & 0 deletions docs/demos/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
categoryOrder: 3
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we can now sort folders!

---

# Demos and examples

While each plugin has its own demo for how to use the plugin (and in combination with other plugins),
there are common behaviors and patterns that can be acheived with the plugin system (with the existing plugins)
that fit more in to a "kitchen-sink" style collection of demos.

If you have an idea for a demo, please [open an issue](https://github.com/CrowdStrike/ember-headless-table/issues)
requesting the demo, or even better, submit a pull request adding your demo.
80 changes: 80 additions & 0 deletions docs/plugins/row-selection/demo/demo-a.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
This demonstrates how to use the RowSelection plugin to enable multiple row selection.
NullVoxPopuli marked this conversation as resolved.
Show resolved Hide resolved
If single-row selection is desired, that can be handled in userspace, by managing the selection data differently (see other demos).

To select a row, click it. To deselect a row, click it again.

```hbs template
<div class="h-full overflow-auto" {{this.table.modifiers.container}}>
<table>
<thead>
<tr>
<td></td>
{{#each this.table.columns as |column|}}
<th {{this.table.modifiers.columnHeader column}} class="relative group">
{{column.name}}
</th>
{{else}}
<th>
No columns are visible
</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each this.table.rows as |row|}}
<tr {{this.table.modifiers.row row}} class="{{if (this.isSelected row) 'bg-surface-inner'}}">
<td>
<button {{on 'click' (fn this.toggle row)}}>Toggle</button>
</td>
{{#each this.table.columns as |column|}}
<td>
{{column.getValueForRow row}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
</div>
```
```js component
import Component from '@glimmer/component';

import { headlessTable } from 'ember-headless-table';
import { meta } from 'ember-headless-table/plugins';
import { TrackedSet } from 'tracked-built-ins';
import { RowSelection, toggle, isSelected } from 'ember-headless-table/plugins/row-selection';

import { DATA } from 'docs-app/sample-data';

export default class extends Component {
selection = new TrackedSet();

table = headlessTable(this, {
columns: () => [
{ name: 'column A', key: 'A' },
{ name: 'column B', key: 'B' },
{ name: 'column C', key: 'C' },
{ name: 'column D', key: 'D' },
],
data: () => DATA,
plugins: [
RowSelection.with(() => {
return {
selection: this.selection,
onSelect: (data) => this.selection.add(data),
onDeselect: (data) => this.selection.delete(data),
};
}),
],
});

/**
* Plugin Integration - all of this can be removed in strict mode, gjs/gts
*
* This syntax looks weird, but it's read as:
* [property on this component] = [variable in scope]
*/
toggle = toggle;
isSelected = isSelected;
}
66 changes: 66 additions & 0 deletions docs/plugins/row-selection/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Row selection

API Documentation available [here][api-docs]

[api-docs]: /api/modules/plugins_row_selection

## Usage

State for what is selected is managed by you, the consumer.
This plugin provides helpful utilities and automatically wires up event listeners for each row.

### ColumnOptions

None


### TableOptions

Required:
- `selection` - a collection of what is already selected
- `onSelect` - event handler for when a row is selected
- `onDeselect` - event handler for when a row is deselected

Optional:
- `key` - a function which will be passed to `onSelect` and `onDeselect` for helping manage "what" is selected. This should be the same data type as the individual elements within the `selection`


See the API Documentation [here][api-docs] for the full list of options and descriptions.

### Preferences

None

### Accessibility

Without a focusable element to trigger a row selection,
keyboard and screen reader users will not be able to select a row.
When using this plugin, ensure that each row has a focusable element that interacts with the selection APIs for that row.

### Helpers + StrictMode

There are convenience helpers for aiding in more ergonomic template usage when using this plugin.

```gjs
import { on } from '@ember/modifier';
import { fn } from '@ember/helper';
import { toggle, isSelected } from 'ember-headless-table/plugins/row-selection';

export const Rows =
<template>
<tbody>
{{#each @table.rows as |row|}}
<tr {{@table.modifiers.row row}} class="{{if (isSelected row) 'bg-surface-inner'}}">
<td>
<button {{on 'click' (fn toggle row)}}>Toggle</button>
</td>
{{#each @table.columns as |column|}}
<td>
{{column.getValueForRow row}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</template>
```
4 changes: 3 additions & 1 deletion docs/plugins/writing-your-own.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The key properties to look at are:
- modifiers -- for interacting with and providing behavior to specific elements
- `containerModifier` - for the table's container div
- `headerCellModifier` - for each `<th>`
- `rowModifier` - **coming soon** - for each `<tr>`
- `rowModifier` - for each `<tr>`
- `reset` -- a hook that the table will call on your plugin if you have state to revert to

With these capabilities, features for tables may be built in a way that relieves implementation complexity on the consumer, such as:
Expand All @@ -50,11 +50,13 @@ class MyPlugin {
meta = {
table: MyTableMeta,
column: MyColumnMeta,
row: MyRowMeta,
}
}

class MyTableMeta {}
class MyColumnMeta {}
class MyRowMeta {}
```

The table itself will create instances of your meta classes for you, only when needed.
Expand Down
4 changes: 4 additions & 0 deletions ember-headless-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"./plugins/column-resizing": "./dist/plugins/column-resizing/index.js",
"./plugins/column-visibility": "./dist/plugins/column-visibility/index.js",
"./plugins/sticky-columns": "./dist/plugins/sticky-columns/index.js",
"./plugins/row-selection": "./dist/plugins/row-selection/index.js",
"./test-support": "./dist/test-support/index.js",
"./addon-main.js": "./addon-main.js"
},
Expand All @@ -46,6 +47,9 @@
"plugins/sticky-columns": [
"./dist/plugins/sticky-columns/index.d.ts"
],
"plugins/row-selection": [
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something we manually have to add for each new plugin?

Maybe this should be a note in CONTRIBUTING

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's something that needs to be added in any package for any public entry point -- it's more "normal npm stuff", if that makes sense.
We probably should have a pointer to some doc talking about this tho.

"./dist/plugins/row-selection/index.d.ts"
],
"test-support": [
"./dist/test-support/index.d.ts"
],
Expand Down
10 changes: 10 additions & 0 deletions ember-headless-table/src/-private/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ export class Table<DataType = unknown> extends Resource<Signature<DataType>> {
},
{ eager: false }
),

row: modifier(
(element: HTMLElement, [row]: [Row<DataType>]): Destructor => {
let modifiers = this.plugins.map((plugin) => plugin.rowModifier);
let composed = composeFunctionModifiers(modifiers);

return composed(element, { row, table: this });
},
{ eager: false }
),
};

/**
Expand Down
30 changes: 27 additions & 3 deletions ember-headless-table/src/plugins/-private/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Table } from '../../-private/table';
import type { ColumnReordering } from '../column-reordering';
import type { ColumnVisibility } from '../column-visibility';
import type { Class, Constructor } from '[private-types]';
import type { Column } from '[public-types]';
import type { Column, Row } from '[public-types]';
import type {
ColumnMetaFor,
ColumnOptionsFor,
Expand All @@ -19,6 +19,7 @@ import type {

const TABLE_META = new Map<string, Map<Class<unknown>, any>>();
const COLUMN_META = new WeakMap<Column, Map<Class<unknown>, any>>();
const ROW_META = new WeakMap<Row, Map<Class<unknown>, any>>();

type InstanceOf<T> = T extends Class<infer Instance> ? Instance : T;

Expand Down Expand Up @@ -250,6 +251,29 @@ export const meta = {
});
},

/**
* @public
*
* For a given row and plugin, return the meta / state bucket for the
* plugin<->row instance pair.
*
* Note that this requires the row instance to exist on the table.
*/
forRow<P extends BasePlugin<any>, Data = unknown>(
row: Row<Data>,
klass: Class<P>
): RowMetaFor<SignatureFrom<P>> {
return getPluginInstance(ROW_META, row, klass, () => {
let plugin = row.table.pluginOf(klass);

assert(`[${klass.name}] cannot get plugin instance of unregistered plugin class`, plugin);
assert(`<#${plugin.name}> plugin does not have meta specified`, plugin.meta);
assert(`<#${plugin.name}> plugin does not specify row meta`, plugin.meta.row);

return new plugin.meta.row(row);
});
},

/**
* @public
*
Expand Down Expand Up @@ -413,10 +437,10 @@ export const options = {
/**
* @private
*/
function getPluginInstance<RootKey extends string | Column<any>, Instance>(
function getPluginInstance<RootKey extends string | Column<any> | Row<any>, Instance>(
map: RootKey extends string
? Map<string, Map<Class<Instance>, Instance>>
: WeakMap<Column, Map<Class<Instance>, Instance>>,
: WeakMap<Column | Row, Map<Class<Instance>, Instance>>,
rootKey: RootKey,
mapKey: Class<Instance>,
factory: () => Instance
Expand Down
9 changes: 9 additions & 0 deletions ember-headless-table/src/plugins/row-selection/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { meta } from '../-private/base';
import { RowSelection } from './plugin';

import type { Row } from '../../-private/row';

export const isSelected = (row: Row<any>) => meta.forRow(row, RowSelection).isSelected;
export const select = (row: Row<any>) => meta.forRow(row, RowSelection).select();
export const deselect = (row: Row<any>) => meta.forRow(row, RowSelection).deselect();
export const toggle = (row: Row<any>) => meta.forRow(row, RowSelection).toggle();
7 changes: 7 additions & 0 deletions ember-headless-table/src/plugins/row-selection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Public API
export * from './helpers';
export { RowSelection as Plugin } from './plugin';
export { RowSelection } from './plugin';

// Public types
export type { Signature } from './plugin';
Loading