-
Notifications
You must be signed in to change notification settings - Fork 34
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
[Issue-126] :: Implement Disclosure component #168
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<div | ||
data-test-ember-headlessui-disclosure-wrapper | ||
class='ember-headlessui-disclosure-wrapper' | ||
> | ||
{{yield | ||
(hash | ||
isOpen=this.isOpen | ||
Button=(component | ||
'disclosure/button' toggleState=this.toggleState isOpen=this.isOpen | ||
) | ||
Panel=(component 'disclosure/panel' isOpen=this.isOpen) | ||
) | ||
}} | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Component from '@glimmer/component'; | ||
|
||
import { action } from '@ember/object'; | ||
import { tracked } from '@glimmer/tracking'; | ||
|
||
export default class Disclosure extends Component { | ||
|
||
@tracked isOpen = false; | ||
|
||
@action | ||
toggleState(){ | ||
this.isOpen = !this.isOpen; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<button | ||
type='button' | ||
aria-haspopup={{true}} | ||
aria-controls={{if @isOpen this.itemsGuid}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we generate a single GUID in the parent component, just to reduce the number of repeat guid creations? passing a guid (and then concatting suffixes) allows us to then also get rid of data-test-selectors (we don't want to ship these to consumers either, but that's a current problem all over the addon that we need to fix -- out of scope for this PR) |
||
aria-expanded={{@isOpen}} | ||
data-test-headlessui-disclosure-button='test-disclosure-btn-{{@index}}' | ||
id={{this.buttonGuid}} | ||
{{on 'click' @toggleState}} | ||
...attributes | ||
> | ||
{{yield}} | ||
</button> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Component from '@glimmer/component'; | ||
|
||
import { action } from '@ember/object'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { guidFor } from '@ember/object/internals'; | ||
|
||
|
||
export default class Button extends Component { | ||
guid = `${guidFor(this)}-tailwindui-disclosure-button`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we use the guid helper instead of having a backing class? template-only components are more performant |
||
|
||
|
||
get itemsGuid() { | ||
return `${this.guid}-items`; | ||
} | ||
|
||
get buttonGuid() { | ||
return `${this.guid}-button`; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{{#if @isOpen}} | ||
<div | ||
id={{this.panelGuid}} | ||
data-test-headlessui-disclosure-panel='disclosure-panel-{{@index}}' | ||
...attributes | ||
> | ||
{{yield}} | ||
</div> | ||
{{/if}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import Component from '@glimmer/component'; | ||
|
||
import { tracked } from '@glimmer/tracking'; | ||
import { guidFor } from '@ember/object/internals'; | ||
|
||
export default class Panel extends Component { | ||
panelGuid = `${guidFor(this)}-tailwindui-disclosure-panel`; | ||
|
||
@tracked isOpen = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why does this have its own isOpen state when the parent component also has isOpen? |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from 'ember-headlessui/components/disclosure'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from 'ember-headlessui/components/disclosure/button'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from 'ember-headlessui/components/disclosure/panel'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<div class='w-full px-4 py-4 pt-16'> | ||
<div class='mx-auto w-full max-w-md bg-white shadow-md px-4 py-4 rounded-lg'> | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button | ||
@index={{1}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we do we have index here? A consumer should never need to manage the index, yeah? |
||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2' | ||
> | ||
<span>What is your refund policy?</span> | ||
<svg | ||
class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' | ||
viewBox='0 0 20 20' | ||
fill='currentColor' | ||
> | ||
<path | ||
fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd' | ||
></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel | ||
@index={{1}} | ||
class='px-4 pt-4 pb-4 text-sm text-gray-500' | ||
> | ||
If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button | ||
@index={{2}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2' | ||
> | ||
<span>Do you provide technical support ?</span> | ||
<svg | ||
class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' | ||
viewBox='0 0 20 20' | ||
fill='currentColor' | ||
> | ||
<path | ||
fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd' | ||
></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel | ||
@index={{2}} | ||
class='px-4 pt-4 pb-4 text-sm text-gray-500' | ||
> | ||
No. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
</div> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<Disclosure::Basic /> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
import { module, test } from 'qunit'; | ||
import { setupRenderingTest } from 'ember-qunit'; | ||
import { click, render} from '@ember/test-helpers'; | ||
|
||
module('Integration | Component | <Disclosure>', (hooks) => { | ||
setupRenderingTest(hooks); | ||
|
||
test('it should render disclosure component', async function (assert) { | ||
await render(hbs` | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{1}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>What is your refund policy?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{1}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
`); | ||
assert.dom('[data-test-ember-headlessui-disclosure-wrapper]').exists(); | ||
}); | ||
|
||
test('it should render disclosure component titles', async function (assert) { | ||
await render(hbs` | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{1}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>What is your refund policy?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{1}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{2}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>Do you provide technical support ?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{2}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
No | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
`); | ||
assert.dom('[data-test-headlessui-disclosure-button="test-disclosure-btn-1"]').hasText('What is your refund policy?') | ||
assert.dom('[data-test-headlessui-disclosure-button="test-disclosure-btn-2"]').hasText('Do you provide technical support ?') | ||
}); | ||
|
||
test('it should render disclosure component panel description', async function (assert) { | ||
await render(hbs` | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{1}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>What is your refund policy?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{1}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{2}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>Do you provide technical support ?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{2}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
No | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
`); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-1"]'); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-2"]'); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-1"]').hasText(`If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked.`); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-2"]').hasText('No'); | ||
}); | ||
|
||
test('check the toggle for disclosure component', async function (assert) { | ||
await render(hbs` | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{1}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>What is your refund policy?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{1}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
If you're unhappy with your purchase for any reason, email us within | ||
90 days and we'll refund you in full, no questions asked. | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
<Disclosure as |disclosure|> | ||
<span class='rounded-md shadow-sm'> | ||
<disclosure.Button @index={{2}} | ||
class='flex mt-2 w-full justify-between rounded-lg bg-indigo-500 px-4 py-2 text-left text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 pb-2 mb-2'> | ||
<span>Do you provide technical support ?</span> | ||
<svg class='w-5 h-5 ml-2 -mr-1 | ||
{{if disclosure.isOpen "transform rotate-180"}}' viewBox='0 0 20 20' fill='currentColor'> | ||
<path fillRule='evenodd' | ||
d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' | ||
clipRule='evenodd'></path> | ||
</svg> | ||
</disclosure.Button> | ||
<disclosure.Panel @index={{2}} class='px-4 pt-4 pb-4 text-sm text-gray-500'> | ||
No | ||
</disclosure.Panel> | ||
</span> | ||
</Disclosure> | ||
`); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-1"]').doesNotExist(); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-1"]'); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-1"]').exists(); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-2"]'); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-2"]').exists(); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-2"]'); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-1"]').exists(); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-2"]').doesNotExist(); | ||
await click('[data-test-headlessui-disclosure-button="test-disclosure-btn-1"]'); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-1"]').doesNotExist(); | ||
assert.dom('[data-test-headlessui-disclosure-panel="disclosure-panel-2"]').doesNotExist(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need the wrapping div?