Skip to content

Commit

Permalink
feat(addon/components/paper-item): converts to a glimmer component.
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewhartstonge committed Nov 13, 2024
1 parent f8d4e76 commit e185cab
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 89 deletions.
83 changes: 59 additions & 24 deletions addon/components/paper-item.hbs
Original file line number Diff line number Diff line change
@@ -1,28 +1,63 @@
{{! template-lint-disable no-action }}
{{#with (hash
checkbox=(component "paper-checkbox" parentComponent=this bubbles=false shouldRegister=true)
button=(component "paper-button" parentComponent=this bubbles=false shouldRegister=true skipProxy=true)
switch=(component "paper-switch" parentComponent=this bubbles=false shouldRegister=true)
radio=(component "paper-radio-proxiable" parentComponent=this bubbles=false shouldRegister=true)
) as |controls|}}
<md-list-item
class='{{if this.hasProxiedComponent " md-proxy-focus"}}
{{if this.shouldBeClickable " md-clickable"}}
{{if this.focused " md-focused"}}
{{if this.hasPrimaryAction " _md-button-wrap"}}
{{@class}}'
role='listitem'
tabindex='-1'
title={{@title}}
{{did-insert this.didInsertNode}}
{{will-destroy this.willDestroyNode}}
{{on 'click' this.localOnClick}}
...attributes
>
{{#with
(hash
checkbox=(component
'paper-checkbox' parentComponent=this bubbles=false shouldRegister=true
)
button=(component
'paper-button'
parentComponent=this
bubbles=false
shouldRegister=true
skipProxy=true
)
switch=(component
'paper-switch' parentComponent=this bubbles=false shouldRegister=true
)
radio=(component
'paper-radio-proxiable'
parentComponent=this
bubbles=false
shouldRegister=true
)
)
as |controls|
}}

{{#if this.hasPrimaryAction}}
<div class="md-button md-no-style">
<PaperButton @class="md-no-style" @onClick={{@onClick}} @href={{@href}} @target={{@target}} @onMouseEnter={{action this.handleMouseEnter}} @onMouseLeave={{action this.handleMouseLeave}} />
<div class="md-list-item-inner">
{{#if this.hasPrimaryAction}}
<div class='md-button md-no-style'>
<PaperButton
@class='md-no-style'
@onClick={{@onClick}}
@href={{@href}}
@target={{@target}}
@onMouseEnter={{this.handleMouseEnter}}
@onMouseLeave={{this.handleMouseLeave}}
/>
<div class='md-list-item-inner'>
{{yield controls}}
</div>
<PaperRipple @noink={{this.noink}} @dimBackground={{true}} />
</div>
{{else}}
<div class='md-no-style md-list-item-inner'>
{{yield controls}}
<PaperRipple @noink={{this.noink}} @dimBackground={{true}} />
</div>
<PaperRipple
@noink={{this.noink}}
@dimBackground={{true}}/>
</div>
{{else}}
<div class="md-no-style md-list-item-inner">
{{yield controls}}
<PaperRipple
@noink={{this.noink}}
@dimBackground={{true}}/>
</div>
{{/if}}
{{/if}}

{{/with}}
{{/with}}
</md-list-item>
176 changes: 111 additions & 65 deletions addon/components/paper-item.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,130 @@
/* eslint-disable ember/no-classic-components, ember/no-computed-properties-in-native-classes */
import {
attributeBindings,
classNameBindings,
tagName,
} from '@ember-decorators/component';
import { computed } from '@ember/object';
import { or, bool, filter } from '@ember/object/computed';

import Component from '@ember/component';
import { ParentMixin } from 'ember-composability-tools';
import { invokeAction } from 'ember-paper/utils/invoke-action';
/**
* @module ember-paper
*/
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array';
import { action } from '@ember/object';

/**
* @class PaperItem
* @extends Ember.Component
* @uses ParentMixin
*/
@tagName('md-list-item')
@classNameBindings(
'hasProxiedComponent:md-proxy-focus',
'shouldBeClickable:md-clickable',
'focused:md-focused',
'hasPrimaryAction:_md-button-wrap'
)
@attributeBindings('role', 'tabindex', 'title')
export default class PaperItem extends Component.extend(ParentMixin) {
_mouseEnterHandler = undefined;
_mouseLeaveHandler = undefined;

// Ripple Overrides
// disable ripple when we have a primary action or when we don't have a proxied component
@computed('hasPrimaryAction', 'hasProxiedComponent')
get noink() {
return this.hasPrimaryAction || !this.hasProxiedComponent;
export default class PaperItem extends Component {
/**
* Reference to the component's DOM element
* @type {HTMLElement}
*/
element;

/**
* Set of child grid tile components
* @type {A}
*/
@tracked children;
@tracked focused = false;

constructor(owner, args) {
super(owner, args);

this.children = A([]);

if (this.args.role) {
this.role = this.args.role;
}
}

role = 'listitem';
tabindex = '-1';
@action didInsertNode(element) {
element.addEventListener('mouseenter', this.handleMouseEnter);
element.addEventListener('mouseleave', this.handleMouseLeave);

@filter('childComponents', function (c) {
return !c.skipProxy;
})
proxiedComponents;
this.element = element;
}

@bool('proxiedComponents.length')
hasProxiedComponent;
@action didUpdateNode() {
// noop
}

@or('hasProxiedComponent', 'onClick')
shouldBeClickable;
@action willDestroyNode(element) {
element.removeEventListener('mouseenter', this.handleMouseEnter);
element.removeEventListener('mouseleave', this.handleMouseLeave);
}

@or('onClick', 'href')
hasPrimaryAction;
/**
* Registers a child component
* @param {Component} child - The component to register
*/
@action registerChild(child) {
this.children.pushObject(child);
}

@computed('hasPrimaryAction', 'hasProxiedComponent')
get noProxy() {
return !this.hasPrimaryAction && !this.hasProxiedComponent;
/**
* Unregisters a child component
* @param {Component} child - The component to unregister
*/
@action unregisterChild(child) {
this.children.removeObject(child);
}

@computed('proxiedComponents.[]')
get secondaryItem() {
let proxiedComponents = this.proxiedComponents;
return proxiedComponents.objectAt(0);
// Ripple Overrides
/**
* disable ripple when we have a primary action or when we don't have a proxied component
* @returns {boolean}
*/
get noink() {
return this.hasPrimaryAction || !this.hasProxiedComponent;
}

didInsertElement() {
super.didInsertElement(...arguments);
/**
* Returns registered child proxy components.
* @returns {Component[]}
*/
get proxiedComponents() {
return this.children.filter((c) => {
return !c.skipProxy;
});
}

this._mouseEnterHandler = this.handleMouseEnter.bind(this);
this._mouseLeaveHandler = this.handleMouseLeave.bind(this);
/**
* @returns {boolean}
*/
get hasProxiedComponent() {
return this.proxiedComponents ? this.proxiedComponents.length > 0 : false;
}

this.element.addEventListener('mouseenter', this._mouseEnterHandler);
this.element.addEventListener('mouseleave', this._mouseLeaveHandler);
/**
* @returns {boolean}
*/
get shouldBeClickable() {
return this.hasProxiedComponent || !!this.args.onClick;
}

willDestroyElement() {
super.willDestroyElement(...arguments);
/**
* @returns {boolean}
*/
get hasPrimaryAction() {
return !!this.args.onClick || !!this.args.href;
}

this.element.removeEventListener('mouseenter', this._mouseEnterHandler);
this.element.removeEventListener('mouseleave', this._mouseLeaveHandler);
/**
* dead code?
* @returns {boolean}
*/
get noProxy() {
return !this.hasPrimaryAction && !this.hasProxiedComponent;
}

this._mouseEnterHandler = undefined;
this._mouseLeaveHandler = undefined;
/**
* Returns a secondary component.
* @returns {Component}
*/
get secondaryItem() {
let proxiedComponents = this.proxiedComponents;
return proxiedComponents.objectAt(0);
}

click() {
@action localOnClick() {
this.proxiedComponents.forEach((component) => {
if (
!!component.processProxy &&
Expand All @@ -94,11 +136,15 @@ export default class PaperItem extends Component.extend(ParentMixin) {
});
}

handleMouseEnter(e) {
invokeAction(this, 'onMouseEnter', e);
@action handleMouseEnter(e) {
if (this.args.onMouseEnter) {
this.args.onMouseEnter(e);
}
}

handleMouseLeave(e) {
invokeAction(this, 'onMouseLeave', e);
@action handleMouseLeave(e) {
if (this.args.onMouseLeave) {
this.args.onMouseLeave(e);
}
}
}

0 comments on commit e185cab

Please sign in to comment.