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

Add preferredPosition to polaris-popover #117

Merged
merged 5 commits into from
Apr 24, 2018

Conversation

tomnez
Copy link
Contributor

@tomnez tomnez commented Apr 23, 2018

Overview

This adds the preferredPosition to the polaris-popover component.

It basically translates the user-provided preferredPosition value into a verticalPosition attribute since we use ember-basic-dropdown as our popover component under the hood.

Test for this is skipped because ember-basic-dropdown uses ember wormhole for the popover content, which renders content outside of the ember testing container.

import layout from '../templates/components/polaris-popover';

const { ViewUtils } = Ember;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hax, suggested by @andrewpye - emberjs/rfcs#168 (comment)

I don't believe there is a way to import these utils using the ES6 modules syntax.

Copy link
Member

@andrewpye andrewpye left a comment

Choose a reason for hiding this comment

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

Just leaving some comments for now to start some discussion, although this does look alright IMO

* @default null
* TODO: not implemented
*/
preferredPosition: null,
Copy link
Member

Choose a reason for hiding this comment

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

This should probably default to below to match the React implementation

// and set when the user opens the popover.

return null;
}),
Copy link
Member

Choose a reason for hiding this comment

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

.readOnly()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This gets set by the onOpen action if the position is set to "mostSpace", so it can't be readOnly

Copy link
Member

Choose a reason for hiding this comment

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

Hmm... seems like an unlikely scenario, but setting this in onOpen will mean that if the host app passes in a dynamic preferredPosition and that value changes from 'mostSpace' after first open, the popover won't honour that change because onOpen will overwrite the CP behaviour here. You could add an explicit setter to this CP, and that way I think that (really tiny) edge case would be avoided...

Copy link
Contributor Author

@tomnez tomnez Apr 24, 2018

Choose a reason for hiding this comment

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

verticalPosition is still a CP, so if preferredPosition dynamically changes, it will re-set verticalPosition to the new value, and then when onOpen runs it will not compute a new value for verticalPosition because it only computes a new value if preferredPosition is set to "mostSpace".

Copy link
Member

Choose a reason for hiding this comment

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

After setting verticalPosition on line 161, my understanding is that verticalPosition will no longer be a CP - the set will replace the entire CP with the literal value that you're setting it to, unless the CP has its own set defined as well. Think of it like this, where someObject is the result of the computed call:

  ... other props...

  myComputed: someObject,

  ... other stuff...

If you then this.set('myComputed', 'something else'), you'll replace someObject with the new string literal. The CP "contained" in someObject will be torn down, and will no longer be computed on dependency changes. From then on, this.get('myComputed') will always return 'something else'.

You can work around this by defining the CP as

myComputed: computed('dep1', 'dep2', {
  get() {
    return 'whatever';
  },

  set(key, value) {
    return value;
  }
),

The set part ensures that the CP remains after a this.set('myComputed', 'something else'), and the value will still update after dep1 or dep2 change...


if (preferredPosition === 'below') {
return preferredPosition;
}
Copy link
Member

Choose a reason for hiding this comment

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

Why not bundle these two into a single if-statement?

let component;

// Hack to get the component's container
// element since this component uses `tagName: ''`
Copy link
Member

Choose a reason for hiding this comment

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

Add a link here to the RFC I linked you to so we know where this came from in the future 👍

Copy link
Member

Choose a reason for hiding this comment

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

(unless of course @vladucu knows any better way to do this?)

Copy link
Member

Choose a reason for hiding this comment

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

good with me for now, ideally I think we should investigate refactoring this at some point and not using ember-basic-dropdown

let preferredPosition = this.get('preferredPosition');

if (preferredPosition === 'mostSpace') {
this.set('verticalPosition', this.mostVerticalSpace());
Copy link
Member

Choose a reason for hiding this comment

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

Not a huge fan of the naming of mostVerticalSpace as a method - it sounds more like a property since there's no verb in the name. How about getMostVerticalSpace or making it a volatile CP and keeping the mostVerticalSpace name?

@@ -6,7 +6,7 @@
component](https://polaris.shopify.com/components/overlays/popover). This component uses [`ember-basic-dropdown`](https://github.com/cibernox/ember-basic-dropdown) to implement popover functionality. Note that the usage is slightly different from the React implementation so please pay attention to the examples below.


**NOTE:** _the `preferredPosition`, `active`, `activatorWrapper`, `preventAutofocus` and `onClose` properties are currently unimplemented._
**NOTE:** _the `active`, `activatorWrapper`, `preventAutofocus` and `onClose` properties are currently unimplemented._
Copy link
Member

Choose a reason for hiding this comment

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

👍

@@ -101,3 +103,29 @@ test('it renders the correct HTML with sectioned attribute', function(assert) {
assert.equal(popoverSections.length, 1, 'renders one popover section');
assert.equal(popoverSections[0].textContent.trim(), 'This is some sectioned popover content', 'popover section contains the correct content');
});

skip('it renders the correct HTML with `prefferedPosition` attribute', function(assert) {
Copy link
Member

Choose a reason for hiding this comment

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

@vladucu what are your thoughts on this test? It's skipped at the moment because it's testing things rendered outside the test div - we can either keep it here and skip it, or maybe look into using document.querySelector etc. instead of the test helpers to retrieve the necessary elements?

Copy link
Member

Choose a reason for hiding this comment

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

yes, I'd lean towards using document.querySelector (or whatever works) and not skip the test if possible

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 I'll see if document.querySelector works

@@ -101,3 +103,29 @@ test('it renders the correct HTML with sectioned attribute', function(assert) {
assert.equal(popoverSections.length, 1, 'renders one popover section');
assert.equal(popoverSections[0].textContent.trim(), 'This is some sectioned popover content', 'popover section contains the correct content');
});

skip('it renders the correct HTML with `prefferedPosition` attribute', function(assert) {
Copy link
Member

Choose a reason for hiding this comment

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

Also @tomnez you've got a typo all over the place with preffered 😛

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tomnez
Copy link
Contributor Author

tomnez commented Apr 24, 2018

@vladucu @andrewpye updated - also I left the controllers/test/index.js file in there because I have found myself repeatedly re-creating it to test new components. Any opposition to this?

@tomnez
Copy link
Contributor Author

tomnez commented Apr 24, 2018

@andrewpye updated! And thanks for the detailed explanations 👍

Copy link
Member

@andrewpye andrewpye left a comment

Choose a reason for hiding this comment

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

Think this is good, one single-quote => double-quote change to make then 🚢 🔥

@@ -1,4 +1,6 @@
{{#basic-dropdown
verticalPosition=verticalPosition
onOpen=(action 'onOpen')
Copy link
Member

Choose a reason for hiding this comment

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

Double-quotes in template files pls 😉

@@ -339,7 +339,7 @@ test('it does not fire actions when disabled days are clicked', function(assert)
year: YEAR,
selected: null,
disableDatesAfter: DISABLE_AFTER,
onChange: (selected) => {
onChange: () => {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure you need the colon here actually


const contentBelow = document.querySelector(popoverContentBelowSelector);
assert.ok(contentBelow, 'renders popover content below the trigger');
});
Copy link
Member

Choose a reason for hiding this comment

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

Love that you got this working 😍

@tomnez tomnez force-pushed the add-positioning-to-polaris-popover branch from e4d261e to ae90dda Compare April 24, 2018 17:13
@tomnez
Copy link
Contributor Author

tomnez commented Apr 24, 2018

@andrewpye updated :shipit:

@tomnez tomnez merged commit 8ffbab7 into master Apr 24, 2018
@tomnez tomnez deleted the add-positioning-to-polaris-popover branch April 24, 2018 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants