From 85e9e764e827f21861f29b35e3b5453a3615e211 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Tue, 25 Apr 2023 10:53:18 -0400
Subject: [PATCH 1/8] Expose named blocks for textarea
---
.../src/-private/textarea-field.hbs | 95 ++++++++++++++++---
.../src/-private/textarea-field.ts | 11 ++-
.../toucan-form/form-textarea-test.gts | 67 +++++++++++++
3 files changed, 156 insertions(+), 17 deletions(-)
diff --git a/packages/ember-toucan-form/src/-private/textarea-field.hbs b/packages/ember-toucan-form/src/-private/textarea-field.hbs
index 8858a87a6..25544ae83 100644
--- a/packages/ember-toucan-form/src/-private/textarea-field.hbs
+++ b/packages/ember-toucan-form/src/-private/textarea-field.hbs
@@ -1,16 +1,83 @@
+{{!
+ Regarding Conditionals
+
+ This looks really messy, but Form::Fields::Textarea exposes named blocks; HOWEVER,
+ we cannot conditionally render named blocks due to https://github.com/emberjs/rfcs/issues/735.
+
+ We *can* conditionally render components though, based on the blocks and argument combinations
+ users provide us. This is very brittle, but until https://github.com/emberjs/rfcs/issues/735
+ is resolved and a solution is found, this appears to be the only way to truly expose
+ conditional named blocks.
+
+ ---
+
+ Regarding glint-expect-error
+
+ "@onChange" of the textarea only expects a string typed value, but field.setValue is generic,
+ accepting anything that DATA[KEY] could be. Similar case with "@value", but there casting to
+ a string is easy.
+}}
<@form.Field @name={{@name}} as |field|>
-
+ {{#if (this.hasOnlyLabelBlock (has-block 'label') (has-block 'hint'))}}
+
+ <:label>{{yield to='label'}}
+
+ {{else if (this.hasHintAndLabelBlocks (has-block 'label') (has-block 'hint'))
+ }}
+
+ <:label>{{yield to='label'}}
+ <:hint>{{yield to='hint'}}
+
+ {{else if (this.hasLabelArgAndHintBlock @label (has-block 'hint'))}}
+
+ <:hint>{{yield to='hint'}}
+
+ {{else}}
+ {{! Argument-only case }}
+
+ {{/if}}
@form.Field>
\ No newline at end of file
diff --git a/packages/ember-toucan-form/src/-private/textarea-field.ts b/packages/ember-toucan-form/src/-private/textarea-field.ts
index ce94d8139..a9164e7ae 100644
--- a/packages/ember-toucan-form/src/-private/textarea-field.ts
+++ b/packages/ember-toucan-form/src/-private/textarea-field.ts
@@ -25,15 +25,20 @@ export interface ToucanFormTextareaFieldComponentSignature<
*/
form: HeadlessFormBlock;
};
- Blocks: {
- default: [];
- };
+ Blocks: BaseTextareaFieldSignature['Blocks'];
}
export default class ToucanFormTextareaFieldComponent<
DATA extends UserData,
KEY extends FormKey> = FormKey>
> extends Component> {
+ hasOnlyLabelBlock = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && !hasHint;
+ hasHintAndLabelBlocks = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && hasHint;
+ hasLabelArgAndHintBlock = (hasLabel: string | undefined, hasHint: boolean) =>
+ hasLabel && hasHint;
+
mapErrors = (errors?: ValidationError[]) => {
if (!errors) {
return;
diff --git a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
index 008859758..af4e4f17d 100644
--- a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
@@ -31,4 +31,71 @@ module('Integration | Component | ToucanForm | Textarea', function (hooks) {
assert.dom('[data-textarea]').hasAttribute('readonly');
});
+
+ test('it renders `@label` and `@hint` component arguments', async function (assert) {
+ const data: TestData = {
+ text: 'multi-line text',
+ };
+
+ await render(
+
+
+
+ );
+
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint]').exists();
+ });
+
+ test('it renders a `:label` named block', async function (assert) {
+ const data: TestData = {
+ text: 'multi-line text',
+ };
+
+ await render(
+
+
+ <:label>Label
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ });
+
+ test('it renders a `:hint` named block', async function (assert) {
+ const data: TestData = {
+ text: 'multi-line text',
+ };
+
+ await render(
+
+
+ <:hint>Hint
+
+
+ );
+
+ // NOTE: `data-label` comes from `@label`.
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
+
+ test('it renders both a `:label` and `:hint` named block', async function (assert) {
+ const data: TestData = {
+ text: 'multi-line text',
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:hint>Hint
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
});
From d64d47c75560498693ab72c01f136a63c61c7356 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 08:09:06 -0400
Subject: [PATCH 2/8] Update
test-app/tests/integration/components/toucan-form/form-textarea-test.gts
Co-authored-by: nicole chung <771170+nicolechung@users.noreply.github.com>
---
.../integration/components/toucan-form/form-textarea-test.gts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
index af4e4f17d..5df8ec1f9 100644
--- a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
@@ -63,7 +63,7 @@ module('Integration | Component | ToucanForm | Textarea', function (hooks) {
assert.dom('[data-label-block]').exists();
});
- test('it renders a `:hint` named block', async function (assert) {
+ test('it renders a `:hint` named block with a @label arg', async function (assert) {
const data: TestData = {
text: 'multi-line text',
};
From 0ac02499eacbe66df93846a5d4bd5c950a7fd9c2 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 08:12:09 -0400
Subject: [PATCH 3/8] tests: Added additional tests for named blocks
---
.../components/toucan-form/form-textarea-test.gts | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
index 5df8ec1f9..b8e50ea93 100644
--- a/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-textarea-test.gts
@@ -47,23 +47,27 @@ module('Integration | Component | ToucanForm | Textarea', function (hooks) {
assert.dom('[data-hint]').exists();
});
- test('it renders a `:label` named block', async function (assert) {
+ test('it renders a `:label` named block with a `@hint` argument', async function (assert) {
const data: TestData = {
text: 'multi-line text',
};
await render(
-
+
<:label>Label
);
assert.dom('[data-label-block]').exists();
+
+ // NOTE: `data-hint` comes from `@hint`.
+ assert.dom('[data-hint]').exists();
+ assert.dom('[data-hint]').hasText('Hint');
});
- test('it renders a `:hint` named block with a @label arg', async function (assert) {
+ test('it renders a `:hint` named block with a `@label` argument', async function (assert) {
const data: TestData = {
text: 'multi-line text',
};
@@ -78,6 +82,8 @@ module('Integration | Component | ToucanForm | Textarea', function (hooks) {
// NOTE: `data-label` comes from `@label`.
assert.dom('[data-label]').exists();
+ assert.dom('[data-label]').hasText('Label');
+
assert.dom('[data-hint-block]').exists();
});
From 84788ef73f0723bb2caf736fd5bf218e73fa3a1f Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 08:22:47 -0400
Subject: [PATCH 4/8] toucan-form: Input named block support
---
.../src/-private/input-field.hbs | 95 ++++++++++++++++---
.../src/-private/input-field.ts | 11 ++-
.../toucan-form/form-input-test.gts | 73 ++++++++++++++
3 files changed, 162 insertions(+), 17 deletions(-)
diff --git a/packages/ember-toucan-form/src/-private/input-field.hbs b/packages/ember-toucan-form/src/-private/input-field.hbs
index b2a61b5f1..37952ab5a 100644
--- a/packages/ember-toucan-form/src/-private/input-field.hbs
+++ b/packages/ember-toucan-form/src/-private/input-field.hbs
@@ -1,16 +1,83 @@
+{{!
+ Regarding Conditionals
+
+ This looks really messy, but Form::Fields::Input exposes named blocks; HOWEVER,
+ we cannot conditionally render named blocks due to https://github.com/emberjs/rfcs/issues/735.
+
+ We *can* conditionally render components though, based on the blocks and argument combinations
+ users provide us. This is very brittle, but until https://github.com/emberjs/rfcs/issues/735
+ is resolved and a solution is found, this appears to be the only way to truly expose
+ conditional named blocks.
+
+ ---
+
+ Regarding glint-expect-error
+
+ "@onChange" of the input only expects a string typed value, but field.setValue is generic,
+ accepting anything that DATA[KEY] could be. Similar case with "@value", but there casting to
+ a string is easy.
+}}
<@form.Field @name={{@name}} as |field|>
-
+ {{#if (this.hasOnlyLabelBlock (has-block 'label') (has-block 'hint'))}}
+
+ <:label>{{yield to='label'}}
+
+ {{else if (this.hasHintAndLabelBlocks (has-block 'label') (has-block 'hint'))
+ }}
+
+ <:label>{{yield to='label'}}
+ <:hint>{{yield to='hint'}}
+
+ {{else if (this.hasLabelArgAndHintBlock @label (has-block 'hint'))}}
+
+ <:hint>{{yield to='hint'}}
+
+ {{else}}
+ {{! Argument-only case }}
+
+ {{/if}}
@form.Field>
\ No newline at end of file
diff --git a/packages/ember-toucan-form/src/-private/input-field.ts b/packages/ember-toucan-form/src/-private/input-field.ts
index d593bfed5..825990b88 100644
--- a/packages/ember-toucan-form/src/-private/input-field.ts
+++ b/packages/ember-toucan-form/src/-private/input-field.ts
@@ -25,15 +25,20 @@ export interface ToucanFormInputFieldComponentSignature<
*/
form: HeadlessFormBlock;
};
- Blocks: {
- default: [];
- };
+ Blocks: BaseInputFieldSignature['Blocks'];
}
export default class ToucanFormInputFieldComponent<
DATA extends UserData,
KEY extends FormKey> = FormKey>
> extends Component> {
+ hasOnlyLabelBlock = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && !hasHint;
+ hasHintAndLabelBlocks = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && hasHint;
+ hasLabelArgAndHintBlock = (hasLabel: string | undefined, hasHint: boolean) =>
+ hasLabel && hasHint;
+
mapErrors = (errors?: ValidationError[]) => {
if (!errors) {
return;
diff --git a/test-app/tests/integration/components/toucan-form/form-input-test.gts b/test-app/tests/integration/components/toucan-form/form-input-test.gts
index 0d58a69e5..31ba4d52f 100644
--- a/test-app/tests/integration/components/toucan-form/form-input-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-input-test.gts
@@ -31,4 +31,77 @@ module('Integration | Component | ToucanForm | Input', function (hooks) {
assert.dom('[data-input]').hasAttribute('readonly');
});
+
+ test('it renders `@label` and `@hint` component arguments', async function (assert) {
+ const data: TestData = {
+ text: 'text',
+ };
+
+ await render(
+
+
+
+ );
+
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint]').exists();
+ });
+
+ test('it renders a `:label` named block with a `@hint` argument', async function (assert) {
+ const data: TestData = {
+ text: 'text',
+ };
+
+ await render(
+
+
+ <:label>Label
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+
+ // NOTE: `data-hint` comes from `@hint`.
+ assert.dom('[data-hint]').exists();
+ assert.dom('[data-hint]').hasText('Hint');
+ });
+
+ test('it renders a `:hint` named block with a `@label` argument', async function (assert) {
+ const data: TestData = {
+ text: 'text',
+ };
+
+ await render(
+
+
+ <:hint>Hint
+
+
+ );
+
+ // NOTE: `data-label` comes from `@label`.
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-label]').hasText('Label');
+
+ assert.dom('[data-hint-block]').exists();
+ });
+
+ test('it renders both a `:label` and `:hint` named block', async function (assert) {
+ const data: TestData = {
+ text: 'text',
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:hint>Hint
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
});
From 5e99d1f1dfa241e6a203add52d9eca713f19bd53 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 08:42:13 -0400
Subject: [PATCH 5/8] toucan-form: Checkbox named block support
---
.../src/-private/checkbox-field.hbs | 95 ++++++++++++++++---
.../src/-private/checkbox-field.ts | 11 ++-
.../toucan-form/form-checkbox-test.gts | 73 ++++++++++++++
3 files changed, 162 insertions(+), 17 deletions(-)
diff --git a/packages/ember-toucan-form/src/-private/checkbox-field.hbs b/packages/ember-toucan-form/src/-private/checkbox-field.hbs
index 66e3ea7e1..750b545a9 100644
--- a/packages/ember-toucan-form/src/-private/checkbox-field.hbs
+++ b/packages/ember-toucan-form/src/-private/checkbox-field.hbs
@@ -1,16 +1,83 @@
+{{!
+ Regarding Conditionals
+
+ This looks really messy, but Form::Fields::Checkbox exposes named blocks; HOWEVER,
+ we cannot conditionally render named blocks due to https://github.com/emberjs/rfcs/issues/735.
+
+ We *can* conditionally render components though, based on the blocks and argument combinations
+ users provide us. This is very brittle, but until https://github.com/emberjs/rfcs/issues/735
+ is resolved and a solution is found, this appears to be the only way to truly expose
+ conditional named blocks.
+
+ ---
+
+ Regarding glint-expect-error
+
+ "@onChange" of the checkbox only expects a boolean typed value, but field.setValue is generic,
+ accepting anything that DATA[KEY] could be. Similar case with "@isChecked", but there casting to
+ a boolean is easy.
+}}
<@form.Field @name={{@name}} as |field|>
-
+ {{#if (this.hasOnlyLabelBlock (has-block 'label') (has-block 'hint'))}}
+
+ <:label>{{yield to='label'}}
+
+ {{else if (this.hasHintAndLabelBlocks (has-block 'label') (has-block 'hint'))
+ }}
+
+ <:label>{{yield to='label'}}
+ <:hint>{{yield to='hint'}}
+
+ {{else if (this.hasLabelArgAndHintBlock @label (has-block 'hint'))}}
+
+ <:hint>{{yield to='hint'}}
+
+ {{else}}
+ {{! Argument-only case }}
+
+ {{/if}}
@form.Field>
\ No newline at end of file
diff --git a/packages/ember-toucan-form/src/-private/checkbox-field.ts b/packages/ember-toucan-form/src/-private/checkbox-field.ts
index fa72d6391..90ec65932 100644
--- a/packages/ember-toucan-form/src/-private/checkbox-field.ts
+++ b/packages/ember-toucan-form/src/-private/checkbox-field.ts
@@ -25,15 +25,20 @@ export interface ToucanFormCheckboxFieldComponentSignature<
*/
form: HeadlessFormBlock;
};
- Blocks: {
- default: [];
- };
+ Blocks: BaseCheckboxFieldSignature['Blocks'];
}
export default class ToucanFormTextareaFieldComponent<
DATA extends UserData,
KEY extends FormKey> = FormKey>
> extends Component> {
+ hasOnlyLabelBlock = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && !hasHint;
+ hasHintAndLabelBlocks = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && hasHint;
+ hasLabelArgAndHintBlock = (hasLabel: string | undefined, hasHint: boolean) =>
+ hasLabel && hasHint;
+
mapErrors = (errors?: ValidationError[]) => {
if (!errors) {
return;
diff --git a/test-app/tests/integration/components/toucan-form/form-checkbox-test.gts b/test-app/tests/integration/components/toucan-form/form-checkbox-test.gts
index 3ff77ff95..acf11e984 100644
--- a/test-app/tests/integration/components/toucan-form/form-checkbox-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-checkbox-test.gts
@@ -31,4 +31,77 @@ module('Integration | Component | ToucanForm | Checkbox', function (hooks) {
assert.dom('[data-checkbox]').hasAttribute('readonly');
});
+
+ test('it renders `@label` and `@hint` component arguments', async function (assert) {
+ const data: TestData = {
+ checked: false,
+ };
+
+ await render(
+
+
+
+ );
+
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint]').exists();
+ });
+
+ test('it renders a `:label` named block with a `@hint` argument', async function (assert) {
+ const data: TestData = {
+ checked: false,
+ };
+
+ await render(
+
+
+ <:label>Label
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+
+ // NOTE: `data-hint` comes from `@hint`.
+ assert.dom('[data-hint]').exists();
+ assert.dom('[data-hint]').hasText('Hint');
+ });
+
+ test('it renders a `:hint` named block with a `@label` argument', async function (assert) {
+ const data: TestData = {
+ checked: false,
+ };
+
+ await render(
+
+
+ <:hint>Hint
+
+
+ );
+
+ // NOTE: `data-label` comes from `@label`.
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-label]').hasText('Label');
+
+ assert.dom('[data-hint-block]').exists();
+ });
+
+ test('it renders both a `:label` and `:hint` named block', async function (assert) {
+ const data: TestData = {
+ checked: false,
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:hint>Hint
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
});
From 6065a25d85b73fb04d5637f8e0ba2ae36d64bcf1 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 12:48:20 -0400
Subject: [PATCH 6/8] toucan-form: CheckboxGroup named block support
---
.../src/-private/checkbox-group-field.hbs | 110 +++++++++++--
.../src/-private/checkbox-group-field.ts | 15 +-
.../toucan-form/form-checkbox-group-test.gts | 149 ++++++++++++++++++
3 files changed, 250 insertions(+), 24 deletions(-)
diff --git a/packages/ember-toucan-form/src/-private/checkbox-group-field.hbs b/packages/ember-toucan-form/src/-private/checkbox-group-field.hbs
index ea2b095c8..bd8a5cb21 100644
--- a/packages/ember-toucan-form/src/-private/checkbox-group-field.hbs
+++ b/packages/ember-toucan-form/src/-private/checkbox-group-field.hbs
@@ -1,19 +1,95 @@
+{{!
+ Regarding Conditionals
+
+ This looks really messy, but Form::Fields::CheckboxGroup exposes named blocks; HOWEVER,
+ we cannot conditionally render named blocks due to https://github.com/emberjs/rfcs/issues/735.
+
+ We *can* conditionally render components though, based on the blocks and argument combinations
+ users provide us. This is very brittle, but until https://github.com/emberjs/rfcs/issues/735
+ is resolved and a solution is found, this appears to be the only way to truly expose
+ conditional named blocks.
+
+ ---
+
+ Regarding glint-expect-error
+
+ "@onChange" of the checkbox-group only expects an array of strings typed value, but field.setValue is generic,
+ accepting anything that DATA[KEY] could be. Similar case with "@isChecked", but there casting to
+ an array of strings is easy.
+}}
<@form.Field @name={{@name}} as |field|>
-
- {{yield (hash CheckboxField=group.CheckboxField)}}
-
+ {{#if (this.hasOnlyLabelBlock (has-block 'label') (has-block 'hint'))}}
+
+ <:label>{{yield to='label'}}
+ <:default as |group|>
+ {{yield (hash CheckboxField=group.CheckboxField) to='default'}}
+
+
+ {{else if (this.hasHintAndLabelBlocks (has-block 'label') (has-block 'hint'))
+ }}
+
+ <:label>{{yield to='label'}}
+ <:hint>{{yield to='hint'}}
+ <:default as |group|>
+ {{yield (hash CheckboxField=group.CheckboxField)}}
+
+
+ {{else if (this.hasLabelArgAndHintBlock @label (has-block 'hint'))}}
+
+ <:hint>{{yield to='hint'}}
+ <:default as |group|>
+ {{yield (hash CheckboxField=group.CheckboxField)}}
+
+
+ {{else}}
+ {{! Argument-only case }}
+
+ {{yield (hash CheckboxField=group.CheckboxField)}}
+
+ {{/if}}
@form.Field>
\ No newline at end of file
diff --git a/packages/ember-toucan-form/src/-private/checkbox-group-field.ts b/packages/ember-toucan-form/src/-private/checkbox-group-field.ts
index 65f1ac455..64b0e540d 100644
--- a/packages/ember-toucan-form/src/-private/checkbox-group-field.ts
+++ b/packages/ember-toucan-form/src/-private/checkbox-group-field.ts
@@ -25,19 +25,20 @@ export interface ToucanFormCheckboxGroupFieldComponentSignature<
*/
form: HeadlessFormBlock;
};
- Blocks: {
- default: [
- {
- CheckboxField: BaseCheckboxGroupFieldSignature['Blocks']['default'][0]['CheckboxField'];
- }
- ];
- };
+ Blocks: BaseCheckboxGroupFieldSignature['Blocks'];
}
export default class ToucanFormTextareaFieldComponent<
DATA extends UserData,
KEY extends FormKey> = FormKey>
> extends Component> {
+ hasOnlyLabelBlock = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && !hasHint;
+ hasHintAndLabelBlocks = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && hasHint;
+ hasLabelArgAndHintBlock = (hasLabel: string | undefined, hasHint: boolean) =>
+ hasLabel && hasHint;
+
mapErrors = (errors?: ValidationError[]) => {
if (!errors) {
return;
diff --git a/test-app/tests/integration/components/toucan-form/form-checkbox-group-test.gts b/test-app/tests/integration/components/toucan-form/form-checkbox-group-test.gts
index dc715abe8..9825141d7 100644
--- a/test-app/tests/integration/components/toucan-form/form-checkbox-group-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-checkbox-group-test.gts
@@ -84,5 +84,154 @@ module(
assert.dom('[data-checkbox-group-2]').hasAttribute('readonly');
assert.dom('[data-checkbox-group-3]').hasNoAttribute('readonly');
});
+
+ test('it renders `@label` and `@hint` component arguments', async function (assert) {
+ const data: TestData = {
+ checkboxes: [],
+ };
+
+ await render(
+
+
+
+
+
+
+
+ );
+
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint]').exists();
+ });
+
+ test('it renders a `:label` named block with a `@hint` argument', async function (assert) {
+ const data: TestData = {
+ checkboxes: [],
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:default as |group|>
+
+
+
+
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+
+ // NOTE: `data-hint` comes from `@hint`.
+ assert.dom('[data-hint]').exists();
+ assert.dom('[data-hint]').hasText('Hint');
+ });
+
+ test('it renders a `:hint` named block with a `@label` argument', async function (assert) {
+ const data: TestData = {
+ checkboxes: [],
+ };
+
+ await render(
+
+
+ <:hint>Hint
+ <:default as |group|>
+
+
+
+
+
+
+ );
+
+ // NOTE: `data-label` comes from `@label`.
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-label]').hasText('Label');
+
+ assert.dom('[data-hint-block]').exists();
+ });
+
+ test('it renders both a `:label` and `:hint` named block', async function (assert) {
+ const data: TestData = {
+ checkboxes: [],
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:hint>Hint
+ <:default as |group|>
+
+
+
+
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
}
);
From 1455a27629dd54e3c98d243932c2a1ac8f11c24c Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Wed, 26 Apr 2023 13:20:00 -0400
Subject: [PATCH 7/8] toucan-form: RadioGroup named block support
---
.../src/-private/radio-group-field.hbs | 110 +++++++++++++---
.../src/-private/radio-group-field.ts | 15 ++-
.../toucan-form/form-radio-group-test.gts | 120 ++++++++++++++++++
3 files changed, 221 insertions(+), 24 deletions(-)
diff --git a/packages/ember-toucan-form/src/-private/radio-group-field.hbs b/packages/ember-toucan-form/src/-private/radio-group-field.hbs
index 828b8303b..c68b4c9b4 100644
--- a/packages/ember-toucan-form/src/-private/radio-group-field.hbs
+++ b/packages/ember-toucan-form/src/-private/radio-group-field.hbs
@@ -1,19 +1,95 @@
+{{!
+ Regarding Conditionals
+
+ This looks really messy, but Form::Fields::RadioGroup exposes named blocks; HOWEVER,
+ we cannot conditionally render named blocks due to https://github.com/emberjs/rfcs/issues/735.
+
+ We *can* conditionally render components though, based on the blocks and argument combinations
+ users provide us. This is very brittle, but until https://github.com/emberjs/rfcs/issues/735
+ is resolved and a solution is found, this appears to be the only way to truly expose
+ conditional named blocks.
+
+ ---
+
+ Regarding glint-expect-error
+
+ "@onChange" of the radio-group only expects a string typed value, but field.setValue is generic,
+ accepting anything that DATA[KEY] could be. Similar case with "@isChecked", but there casting to
+ a string is easy.
+}}
<@form.Field @name={{@name}} as |field|>
-
- {{yield (hash RadioField=group.RadioField)}}
-
+ {{#if (this.hasOnlyLabelBlock (has-block 'label') (has-block 'hint'))}}
+
+ <:label>{{yield to='label'}}
+ <:default as |group|>
+ {{yield (hash RadioField=group.RadioField)}}
+
+
+ {{else if (this.hasHintAndLabelBlocks (has-block 'label') (has-block 'hint'))
+ }}
+
+ <:label>{{yield to='label'}}
+ <:hint>{{yield to='hint'}}
+ <:default as |group|>
+ {{yield (hash RadioField=group.RadioField)}}
+
+
+ {{else if (this.hasLabelArgAndHintBlock @label (has-block 'hint'))}}
+
+ <:hint>{{yield to='hint'}}
+ <:default as |group|>
+ {{yield (hash RadioField=group.RadioField)}}
+
+
+ {{else}}
+ {{! Argument-only case }}
+
+ {{yield (hash RadioField=group.RadioField)}}
+
+ {{/if}}
@form.Field>
\ No newline at end of file
diff --git a/packages/ember-toucan-form/src/-private/radio-group-field.ts b/packages/ember-toucan-form/src/-private/radio-group-field.ts
index 60ba5ecbf..e82d9143e 100644
--- a/packages/ember-toucan-form/src/-private/radio-group-field.ts
+++ b/packages/ember-toucan-form/src/-private/radio-group-field.ts
@@ -25,19 +25,20 @@ export interface ToucanFormRadioGroupFieldComponentSignature<
*/
form: HeadlessFormBlock;
};
- Blocks: {
- default: [
- {
- RadioField: BaseRadioGroupFieldSignature['Blocks']['default'][0]['RadioField'];
- }
- ];
- };
+ Blocks: BaseRadioGroupFieldSignature['Blocks'];
}
export default class ToucanFormTextareaFieldComponent<
DATA extends UserData,
KEY extends FormKey> = FormKey>
> extends Component> {
+ hasOnlyLabelBlock = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && !hasHint;
+ hasHintAndLabelBlocks = (hasLabel: boolean, hasHint: boolean) =>
+ hasLabel && hasHint;
+ hasLabelArgAndHintBlock = (hasLabel: string | undefined, hasHint: boolean) =>
+ hasLabel && hasHint;
+
mapErrors = (errors?: ValidationError[]) => {
if (!errors) {
return;
diff --git a/test-app/tests/integration/components/toucan-form/form-radio-group-test.gts b/test-app/tests/integration/components/toucan-form/form-radio-group-test.gts
index 44a1ac7d8..8af891945 100644
--- a/test-app/tests/integration/components/toucan-form/form-radio-group-test.gts
+++ b/test-app/tests/integration/components/toucan-form/form-radio-group-test.gts
@@ -58,4 +58,124 @@ module('Integration | Component | ToucanForm | RadioGroup', function (hooks) {
assert.dom('[data-radio-1]').hasNoAttribute('readonly');
assert.dom('[data-radio-2]').hasAttribute('readonly');
});
+
+ test('it renders `@label` and `@hint` component arguments', async function (assert) {
+ const data: TestData = {
+ radio: 'option-2',
+ };
+
+ await render(
+
+
+
+
+
+
+ );
+
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-hint]').exists();
+ });
+
+ test('it renders a `:label` named block with a `@hint` argument', async function (assert) {
+ const data: TestData = {
+ radio: 'option-2',
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:default as |group|>
+
+
+
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+
+ // NOTE: `data-hint` comes from `@hint`.
+ assert.dom('[data-hint]').exists();
+ assert.dom('[data-hint]').hasText('Hint');
+ });
+
+ test('it renders a `:hint` named block with a `@label` argument', async function (assert) {
+ const data: TestData = {
+ radio: 'option-2',
+ };
+
+ await render(
+
+
+ <:hint>Hint
+ <:default as |group|>
+
+
+
+
+
+ );
+
+ // NOTE: `data-label` comes from `@label`.
+ assert.dom('[data-label]').exists();
+ assert.dom('[data-label]').hasText('Label');
+
+ assert.dom('[data-hint-block]').exists();
+ });
+
+ test('it renders both a `:label` and `:hint` named block', async function (assert) {
+ const data: TestData = {
+ radio: 'option-2',
+ };
+
+ await render(
+
+
+ <:label>Label
+ <:hint>Hint
+ <:default as |group|>
+
+
+
+
+
+ );
+
+ assert.dom('[data-label-block]').exists();
+ assert.dom('[data-hint-block]').exists();
+ });
});
From 20d433f330a4a6ee3a5d31acfc20f48ccc1bb950 Mon Sep 17 00:00:00 2001
From: Tony Ward <8069555+ynotdraw@users.noreply.github.com>
Date: Thu, 27 Apr 2023 12:59:19 -0400
Subject: [PATCH 8/8] Added changeset
---
.changeset/light-olives-notice.md | 38 +++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 .changeset/light-olives-notice.md
diff --git a/.changeset/light-olives-notice.md b/.changeset/light-olives-notice.md
new file mode 100644
index 000000000..d54fd3057
--- /dev/null
+++ b/.changeset/light-olives-notice.md
@@ -0,0 +1,38 @@
+---
+'@crowdstrike/ember-toucan-form': patch
+---
+
+Exposed named blocks from the underlying `toucan-core` components. This allows users to add custom content in `:hint` or `:label` named blocks. You can combine the arguments and named blocks as well! Below are some examples.
+
+```hbs
+
+
+ <:label>Label
+ <:hint>Hint
+
+
+```
+
+```hbs
+
+
+ <:hint>Hint
+
+
+```
+
+```hbs
+
+
+ <:label>Label
+
+
+```
+
+Or you can continue to use the arguments if you're only working with strings!
+
+```hbs
+
+
+
+```