Skip to content

Commit

Permalink
Merge pull request #88 from bustle/component-name-hooks
Browse files Browse the repository at this point in the history
Provide alternative to inheritance for customizing component paths
  • Loading branch information
lukemelia authored Oct 19, 2022
2 parents eac9aaf + acf31cb commit a5d12bd
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 18 deletions.
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Provides:

* Component `{{render-mobiledoc}}` for rendering mobiledoc in your ember app
* Component `<RenderMobiledoc ... />` for rendering mobiledoc in your ember app
* (For advanced use) The ability to import the [`mobiledoc-dom-renderer`](https://github.com/bustlelabs/mobiledoc-dom-renderer) class

To learn more about mobiledoc see [mobiledoc-kit](https://github.com/bustlelabs/mobiledoc-kit).
Expand All @@ -23,15 +23,15 @@ To learn more about mobiledoc see [mobiledoc-kit](https://github.com/bustlelabs/
#### Render basic mobiledoc in your template

```hbs
{{render-mobiledoc mobiledoc=myMobileDoc}}
<RenderMmobiledoc @mobiledoc={{myMobileDoc}} />
```

#### Render mobiledoc with cards, using ember components to render cards

```hbs
{{! myMobiledoc is the mobiledoc you want to render }}
{{! myCardNames is an array of card names, e.g. ['embed-card', 'slideshow-card'] }}
{{render-mobiledoc mobiledoc=myMobileDoc cardNames=myCardNames}}
<RenderMmobiledoc @mobiledoc={{myMobileDoc}} @cardNames={{myCardNames}} />
```

The ember components with names matching the mobiledoc card names will be rendered
Expand All @@ -40,19 +40,30 @@ The ember components will be in a wrapper div with the class '__rendered-mobiled

#### Customizing card lookup

If your mobiledoc card names do not match component names, you can subclass
the `render-mobiledoc` component and override its `cardNameToComponentName` method.
If your mobiledoc card names do not match component names, you can pass an argument to
the `<RenderMobiledoc...>` component to provide your own mapping.

E.g.:

```hbs
// components/my-component.hbs
<RenderMobiledoc
@mobiledoc={{...}}
@cardNameToComponentName={{this.cardNameToComponentName}}
/>
```

```javascript
// components/my-render-mobiledoc.js
import RenderMobiledoc from 'ember-mobiledoc-dom-renderer/components/render-mobiledoc';
export default RenderMobiledoc.extend({
// components/my-component.js
import Component from '@glimmer/component';
import { action } from '@ember/object';

export default class extends Component {
@action
cardNameToComponentName(mobiledocCardName) {
return 'cards/' + mobiledocCardName;
}
});
}
```

#### Render mobiledoc with atoms, using ember components to render atoms
Expand All @@ -61,13 +72,13 @@ This works the same way as rendering mobiledoc with ember components for cards.
To pass atom names to the renderer, use the `atomNames` property, e.g.:
```hbs
{{! myAtomNames is an array of atom names, e.g. ['mention-atom'] }}
{{render-mobiledoc mobiledoc=myMobileDoc atomNames=myAtomNames}}
<RenderMobiledoc @mobiledoc={{myMobileDoc}} @atomNames={{myAtomNames}} />
```

The component will be passed a `payload` and `value` property.

To customize atom lookup, extend the `render-mobiledoc` component and override
its `atomNameToComponentName` method.
To customize atom lookup, pass an `atomNameToComponentName` argument similar to
what is shown above for `cardNameToComponentName`.

#### Customizing markup and section rendering
The `sectionElementRenderer` and `markupElementRenderer` options can be used to
Expand All @@ -76,7 +87,7 @@ customize the elements used for sections and inline text decorations respectivel
E.g.:

```hbs
{{render-mobiledoc mobiledoc=myMobileDoc sectionElementRenderer=mySectionElementRenderer}}
<RenderMobiledoc @mobiledoc={{this.myMobileDoc}} @sectionElementRenderer={{this.mySectionElementRenderer}} />
```

```js
Expand All @@ -92,7 +103,7 @@ mySectionElementRenderer: {
#### Use mobiledoc-dom-renderer directly

This addon provides the mobiledoc-dom-renderer directly. Most of the time
you will want to use the `{{render-mobiledoc}}` component, but if you need
you will want to use the `<RenderMobiledoc />` component, but if you need
to use the renderer directly in code, it can be imported:

`import DOMRenderer from 'ember-mobiledoc-dom-renderer'`;
Expand Down
10 changes: 8 additions & 2 deletions addon/components/render-mobiledoc/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,19 @@ export default class extends Component {
return super.willDestroy(...arguments);
}

// override in subclass to change the mapping of card name -> component name
// pass the argument to change the mapping of card name -> component name
cardNameToComponentName(name) {
if (this.args.cardNameToComponentName) {
return this.args.cardNameToComponentName(name);
}
return name;
}

// override in subclass to change the mapping of atom name -> component name
// pass the argument to change the mapping of atom name -> component name
atomNameToComponentName(name) {
if (this.args.atomNameToComponentName) {
return this.args.atomNameToComponentName(name);
}
return name;
}

Expand Down
43 changes: 41 additions & 2 deletions tests/integration/components/render-mobiledoc-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module('Integration | Component | render-mobiledoc', function (hooks) {
.exists(`renders card with class ${CARD_ELEMENT_CLASS}-${cardName}`);
});

test('it uses `cardNameToComponentName` to allow selecting components', async function (assert) {
test('it uses `cardNameToComponentName` to allow selecting components (inheritance)', async function (assert) {
this.set('mobiledoc', createMobiledocWithCard(cardName));
this.set('cardNames', [cardName]);

Expand All @@ -62,6 +62,24 @@ module('Integration | Component | render-mobiledoc', function (hooks) {
.hasText('foo: bar', 'renders card payload');
});

test('it uses `cardNameToComponentName` to allow selecting components (arg)', async function (assert) {
this.set('mobiledoc', createMobiledocWithCard(cardName));
this.set('cardNames', [cardName]);
this.set('cardNameToComponentName', (cardName) => {
return cardName.replace('sample', 'sample-changed-name');
});
await render(
hbs`<RenderMobiledoc @mobiledoc={{this.mobiledoc}} @cardNames={{this.cardNames}} @cardNameToComponentName={{this.cardNameToComponentName}} />`
);
assert.dom('#sample-test-card').doesNotExist();
assert
.dom('#sample-changed-name-test-card')
.exists('renders card template');
assert
.dom('#sample-changed-name-test-card')
.hasText('foo: bar', 'renders card payload');
});

test('it renders mobiledoc with atoms', async function (assert) {
this.set('mobiledoc', createMobiledocWithAtom(atomName));
this.set('atomNames', [atomName]);
Expand All @@ -84,7 +102,7 @@ module('Integration | Component | render-mobiledoc', function (hooks) {
.exists(`renders atom with class ${ATOM_ELEMENT_CLASS}-${atomName}`);
});

test('it uses `atomNameToComponentName` to allow selecting components', async function (assert) {
test('it uses `atomNameToComponentName` to allow selecting components (inheritance)', async function (assert) {
this.set('mobiledoc', createMobiledocWithAtom(atomName));
this.set('atomNames', [atomName]);

Expand All @@ -105,6 +123,27 @@ module('Integration | Component | render-mobiledoc', function (hooks) {
.includesText('payload: bar', 'renders atom payload');
});

test('it uses `atomNameToComponentName` to allow selecting components (arg)', async function (assert) {
this.set('mobiledoc', createMobiledocWithAtom(atomName));
this.set('atomNames', [atomName]);
this.set('atomNameToComponentName', (atomName) => {
return atomName.replace('sample', 'sample-changed-name');
});
await render(
hbs`<RenderMobiledoc @mobiledoc={{this.mobiledoc}} @atomNames={{this.atomNames}} @atomNameToComponentName={{this.atomNameToComponentName}} />`
);
assert.dom('#sample-test-atom').doesNotExist();
assert
.dom('#sample-changed-name-test-atom')
.exists('renders atom template');
assert
.dom('#sample-changed-name-test-atom')
.includesText('value: value', 'renders atom value');
assert
.dom('#sample-changed-name-test-atom')
.includesText('payload: bar', 'renders atom payload');
});

test("it does not rerender if a atom component changes its card's payload or value", async function (assert) {
let inserted = 0;
let atom;
Expand Down

0 comments on commit a5d12bd

Please sign in to comment.