Conversation
WalkthroughThis pull request adds comprehensive freestyle documentation and interactive demo infrastructure for a component library (Irene Components). It introduces 70+ new files including demo components, Handlebars templates, routing, styling, and an ember-freestyle integration for showcasing 36 UI components with interactive examples and usage patterns. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Stylelint (17.4.0)app/styles/_freestyle.scssAllFilesIgnoredError: All input files were ignored because of the ignore pattern. Either change your input, ignore pattern or use "--allow-empty-input" to allow no inputs app/styles/app.scssAllFilesIgnoredError: All input files were ignored because of the ignore pattern. Either change your input, ignore pattern or use "--allow-empty-input" to allow no inputs Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Deploying irenestaging with
|
| Latest commit: |
6a9f981
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://089ad83a.irenestaging.pages.dev |
| Branch Preview URL: | https://pd-2208-ember-freestyle.irenestaging.pages.dev |
Irene
|
||||||||||||||||||||||||||||||||||
| Project |
Irene
|
| Branch Review |
PD-2208-Ember-Freestyle
|
| Run status |
|
| Run duration | 04m 10s |
| Commit |
|
| Committer | SmitGala |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
1
|
|
|
0
|
|
|
1
|
|
|
0
|
|
|
30
|
| View all changes introduced in this branch ↗︎ | |
Tests for review
cypress/tests/dynamic-scan.spec.ts • 1 failed test
| Test | Artifacts | |
|---|---|---|
| Dynamic Scan > it tests dynamic scan for an apk file: 132571 |
Test Replay
Screenshots
|
|
There was a problem hiding this comment.
Actionable comments posted: 15
🧹 Nitpick comments (16)
app/components/ak-list/freestyle-demo.hbs (1)
5-11: Consider forwarding@noGuttersfrom args instead of hardcoding.Line 8 hardcodes
@noGutters={{false}}, but based on the component signature described in the summary, this should likely be@noGutters={{@noGutters}}to allow the freestyle section to demonstrate different gutter configurations.💡 Suggested fix
<akl.listItem `@button`={{`@button`}} `@link`={{`@link`}} - `@noGutters`={{false}} + `@noGutters`={{`@noGutters`}} `@disabled`={{`@disabled`}} `@selected`={{`@selected`}} as |li|🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-list/freestyle-demo.hbs` around lines 5 - 11, The template hardcodes `@noGutters`={{false}} on the akl.listItem invocation; change it to forward the incoming arg by replacing the hardcoded value with `@noGutters`={{`@noGutters`}} so the freestyle-demo can demonstrate different gutter configurations—update the akl.listItem invocation in the freestyle-demo.hbs to use the `@noGutters` arg passed into the component.app/components/ak-tree/freestyle-demo.ts (2)
10-18: Potentially confusingexpanded: truein static data.The
expanded: trueproperty onChild1.1inTREE_DATAmay be misleading since the component manages expansion state via the@tracked expandedarray (initialized to['Root1', 'Root2']), not through this property. Consider removing it if it's not used byAkTree, or add a comment clarifying its purpose.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-tree/freestyle-demo.ts` around lines 10 - 18, The TREE_DATA entry for the node with key 'Child1.1' currently includes expanded: true which conflicts with or misleads about the component-controlled expansion state held in the `@tracked` expanded array (initialized to ['Root1', 'Root2']); either remove the expanded property from the static TREE_DATA node or add a brief comment next to the 'Child1.1' node explaining it is unused by AkTree and kept only for illustrative/legacy purposes so readers aren’t confused by the component’s actual expansion source.
37-39: Consider documenting the magic number incalculatePadding.The multiplier
0.9286appears to be a specific design constant. A brief comment explaining the rationale (e.g., alignment with a design system's spacing scale) would improve maintainability.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-tree/freestyle-demo.ts` around lines 37 - 39, Document the magic multiplier used in calculatePadding: add a short explanatory comment above calculatePadding (or extract 0.9286 into a well-named constant like PADDING_SCALE) that explains why 0.9286 is used (e.g., alignment with the design system's spacing scale or conversion from pixel values), reference the calculatePadding(treeDepth: number) function and ensure the comment mentions the expected units (em) and any source or formula for the value so future maintainers understand and can update it safely.app/routes/freestyle/component.ts (1)
38-40: Prefer a canonical redirect for unknown component IDs.Line 40 silently maps any invalid slug to
'ak-accordion', so/freestyle/not-a-real-componentwill render accordion content under a bogus URL. Redirect to the default component route, or show a not-found state instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/routes/freestyle/component.ts` around lines 38 - 40, The model function currently silently maps invalid slugs to 'ak-accordion'; update model(params: { component_id?: string }) to detect when params.component_id is not in VALID_COMPONENTS and then perform a canonical redirect to the default route (e.g. redirect to '/freestyle/ak-accordion') or return a proper not-found response (e.g. throw a 404 Response) instead of returning 'ak-accordion'. Use the same VALID_COMPONENTS check to decide and invoke your framework's redirect/response mechanism from within model rather than silently substituting the id.app/components/freestyle-section.ts (1)
3-6: Consider addingoverridekeyword toshowgetter.For consistency with TypeScript best practices and to explicitly signal the intention to override a base class member, consider adding the
overridekeyword.♻️ Suggested change
export default class FreestyleSection extends FreestyleSectionAddon { - get show(): boolean { + override get show(): boolean { return true; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/freestyle-section.ts` around lines 3 - 6, The show getter in class FreestyleSection is intended to override the base class member from FreestyleSectionAddon; add the TypeScript override modifier to the getter (i.e., declare `override get show(): boolean`) in the FreestyleSection class to make the override explicit and consistent with TS best practices.app/styles/_freestyle.scss (1)
1-8: Note: Using!importantto override third-party styles.The
!importantdeclarations are acceptable here for overriding ember-freestyle's built-in header elements. Consider adding a brief comment clarifying this is intentional to prevent future developers from thinking it's a code smell.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/styles/_freestyle.scss` around lines 1 - 8, Add a short explanatory comment above the rules indicating the use of !important is intentional to override ember-freestyle defaults, so future maintainers won't remove it; reference the selector block (.FreestyleGuide-header, .FreestyleGuide-cta, .FreestyleGuide-nav, .FreestyleGuide-aside) and state that we hide the built-in header/sidebar in favor of our own sidebar and therefore need the !important overrides.app/components/freestyle-usage.ts (1)
3-6: Consider addingoverridekeyword toshowgetter for consistency.The
hasCodegetter uses theoverridekeyword, butshowdoes not. For consistency and to make the intent explicit, consider adding it.♻️ Suggested change
export default class FreestyleUsage extends FreestyleUsageAddon { - get show(): boolean { + override get show(): boolean { return true; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/freestyle-usage.ts` around lines 3 - 6, The show getter in class FreestyleUsage lacks the override keyword while other inherited getters (e.g., hasCode) use it; update the show getter in FreestyleUsage to include the override modifier (i.e., change the declaration of the show getter in FreestyleUsage to explicitly use override) so the intent is clear and consistent with hasCode.app/components/freestyle-nav.ts (1)
3-35: Consider adding TypeScript typing for better type safety.The component entries would benefit from explicit typing for improved developer experience and type safety.
♻️ Proposed type definition
import Component from '@glimmer/component'; +interface ComponentNavItem { + id: string; + label: string; +} + -const COMPONENTS = [ +const COMPONENTS: readonly ComponentNavItem[] = [ { id: 'ak-accordion', label: 'Accordion' }, // ... rest of entries -]; +] as const;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/freestyle-nav.ts` around lines 3 - 35, The COMPONENTS array lacks explicit TypeScript types; define a small interface or type (e.g., ComponentItem with id: string and label: string) and annotate COMPONENTS as ComponentItem[] (or readonly ComponentItem[] if immutable) so each entry (the objects in COMPONENTS) is type-checked; update any exports/usages of COMPONENTS to use the new type for better autocomplete and compile-time safety.app/components/ak-tabs/freestyle-demo.hbs (1)
16-16: Avoid using!importantin inline styles.Using
!importantin inline styles is generally a code smell and can make styles difficult to override. Consider addressing the underlying specificity issue in the component's CSS instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-tabs/freestyle-demo.hbs` at line 16, The inline style on AkIcon using "!important" should be removed; instead, create a CSS rule (e.g., .ak-icon--large or a contextual selector in the freestyle-demo component stylesheet) that sets font-size: 1.29rem with appropriate specificity, then replace the inline {{style ...}} usage in the template by adding that class to the AkIcon invocation (AkIcon `@iconName`={{item.iconName}} class="ak-icon--large" or the equivalent class-binding in the template) so styling is controlled via stylesheet rather than an inline !important.app/components/ak-chip/freestyle-section.hbs (1)
22-27: Consider clarifying the "Deletable" terminology.The section is labeled "Deletable" but uses
@button={{true}}which makes the chip clickable, not specifically deletable. If the intent is to demonstrate delete functionality, consider adding an@onDeletehandler or renaming this section to "Clickable" or "Button Chips" to avoid confusion for developers using this documentation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-chip/freestyle-section.hbs` around lines 22 - 27, The "Deletable" demo uses AkChip with `@button`={{true}} which only makes chips clickable, causing mismatch with the title; either rename the FreestyleUsage title from 'Deletable' to 'Clickable' or 'Button Chips', or update the AkChip examples to demonstrate actual delete behavior by adding an `@onDelete` handler to each <AkChip> (and optionally keep `@button` if both behaviours are supported) so the section label matches the implemented interactivity; look for the FreestyleUsage block and AkChip components in this snippet to apply the change.app/components/freestyle-component-renderer.hbs (1)
1-66: Move the component registry out of the template.This
else ifladder requires manual synchronization: every new showcase must be added to both the template branches and the filesystem. A registry-based approach using a lightweight TypeScript map and dynamic component lookup would eliminate this source of drift and make extensions less error-prone.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/freestyle-component-renderer.hbs` around lines 1 - 66, The template's long else-if ladder (checking `@componentId` and rendering AkX::FreestyleSection) should be replaced by a TS registry and dynamic lookup: create a lightweight module (e.g., freestyle-component-registry.ts) that exports a map from componentId strings (like "ak-accordion") to the corresponding component reference/name (the same values currently used in the template, e.g., "AkAccordion::FreestyleSection"); update the component backing class for this template (FreestyleComponentRenderer) to import that registry and expose a computed/derived property (e.g., selectedComponent) that returns registry[this.args.componentId] or null; then simplify the HBS to render dynamically via the component helper (e.g., {{`#if` this.selectedComponent}}{{component this.selectedComponent}}{{else}}<p class='text-secondary'>Component not found: {{`@componentId`}}</p>{{/if}}). This moves the registry out of freestyle-component-renderer.hbs into a single source of truth and uses `@componentId`, FreestyleComponentRenderer, selectedComponent, and the component helper for the dynamic lookup.app/components/ak-icon-button/freestyle-section.hbs (1)
5-8: Omit the@colorargument instead of passing an empty string.
@color=''relies on treating empty string as falsy to default toinherit. Omitting the argument is clearer, safer, and aligns with the type definition which doesn't include empty string as a validAkIconColorVariantvalue.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-icon-button/freestyle-section.hbs` around lines 5 - 8, The AkIcon components are passing `@color`='' which relies on an empty string as falsy; remove the `@color`='' attribute from the AkIcon tags (e.g., the AkIcon instances nested in AkIconButton with `@iconName`='close' and `@iconName`='refresh') so the prop is omitted and the component falls back to the intended default (inherit) that matches the AkIconColorVariant type.app/components/ak-pagination/freestyle-demo.ts (1)
16-32: Collapse the repeated pagination updates into one helper.These three actions currently duplicate the same state transition. Pulling the assignments into one helper keeps future pagination changes from diverging.
♻️ Proposed fix
+type PaginationArgs = { limit: number; offset: number }; + export default class AkPaginationFreestyleDemoComponent extends Component { totalPaginationData = TOTAL_DATA; `@tracked` limit = 5; `@tracked` offset = 0; get tableData() { return this.totalPaginationData.slice(this.offset, this.limit + this.offset); } + private updatePagination({ limit, offset }: PaginationArgs) { + this.limit = limit; + this.offset = offset; + } + `@action` - onItemPerPageChange(args: { limit: number; offset: number }) { - this.limit = args.limit; - this.offset = args.offset; + onItemPerPageChange(args: PaginationArgs) { + this.updatePagination(args); } `@action` - nextAction(args: { limit: number; offset: number }) { - this.limit = args.limit; - this.offset = args.offset; + nextAction(args: PaginationArgs) { + this.updatePagination(args); } `@action` - prevAction(args: { limit: number; offset: number }) { - this.limit = args.limit; - this.offset = args.offset; + prevAction(args: PaginationArgs) { + this.updatePagination(args); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-pagination/freestyle-demo.ts` around lines 16 - 32, The three actions onItemPerPageChange, nextAction, and prevAction duplicate setting this.limit and this.offset; extract a single helper method (e.g., updatePagination or setPagination) that accepts { limit, offset } and performs the assignments, then have each action call that helper instead of repeating the two assignments so future pagination logic is centralized.app/components/ak-select/freestyle-demo.ts (1)
13-13: Drop the no-op non-null assertion.
SELECT_ITEMS[0]!is already typed asSelectItemhere, so!does not narrow anything and just adds noise.♻️ Proposed fix
-const DEFAULT_ITEM: SelectItem = SELECT_ITEMS[0]!; +const DEFAULT_ITEM: SelectItem = SELECT_ITEMS[0];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-select/freestyle-demo.ts` at line 13, DEFAULT_ITEM is initialized with SELECT_ITEMS[0]! using a no-op non-null assertion; remove the trailing "!" so the initializer reads SELECT_ITEMS[0] and let the declared type SelectItem handle typing. Update the declaration of DEFAULT_ITEM (symbol DEFAULT_ITEM) to use SELECT_ITEMS[0] without "!" to eliminate the unnecessary assertion.app/components/ak-pagination/freestyle-demo.hbs (1)
5-5: Derive@totalItemsfrom the backing dataset.
@totalItems={{50}}is a second source of truth for the demo count. IfTOTAL_DATAchanges, the pagination footer and navigation state will drift from the actual dataset.♻️ Proposed fix
- `@totalItems`={{50}} + `@totalItems`={{this.totalPaginationData.length}}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-pagination/freestyle-demo.hbs` at line 5, The template currently hardcodes `@totalItems`={{50}} which diverges from the actual dataset; remove the literal and derive totalItems from the backing dataset (TOTAL_DATA) instead — either pass TOTAL_DATA.length directly into the template (e.g. `@totalItems`={{TOTAL_DATA.length}}) or compute a getter/property (e.g. totalItems) in the freestyle-demo component/controller that returns TOTAL_DATA.length and reference that property in the template (replace `@totalItems` with `@totalItems`={{this.totalItems}}); ensure any code that uses `@totalItems` (pagination component) continues to receive the dynamic value.app/components/ak-toggle/freestyle-demo.ts (1)
28-32: Avoid mapping unknown sizes tolarge.Line 32's fallback
elsemutatescheckedLargefor any unexpected runtime value, which can mask a bad template arg and show the wrong demo state. Make the'large'branch explicit and ignore or assert on unknown input instead.Proposed refactor
`@action` handleSizeChange(size: 'small' | 'medium' | 'large', _event: Event, checked: boolean) { - if (size === 'small') this.checkedSmall = checked; - else if (size === 'medium') this.checkedMedium = checked; - else this.checkedLarge = checked; + if (size === 'small') { + this.checkedSmall = checked; + } else if (size === 'medium') { + this.checkedMedium = checked; + } else if (size === 'large') { + this.checkedLarge = checked; + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/ak-toggle/freestyle-demo.ts` around lines 28 - 32, The handler handleSizeChange currently treats any non-'small'/'medium' value as 'large', which can mask bad inputs; update handleSizeChange to explicitly check for size === 'large' and set checkedLarge only in that branch, and for any other unexpected size either ignore the call (no state change) or throw/assert (e.g. throw new Error or console.warn) so invalid values are not silently mapped to checkedLarge; reference the properties checkedSmall, checkedMedium, and checkedLarge when implementing the explicit branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/components/ak-appbar/freestyle-section.hbs`:
- Around line 15-18: The trailing icon-only button (AkIconButton in
freestyle-section.hbs) lacks an accessible name; add an aria-label (e.g.,
aria-label="Close") to the AkIconButton element so screen readers announce the
action—ensure the attribute is set on the AkIconButton component (not just
AkIcon) to provide the accessible name.
In `@app/components/ak-checkbox/freestyle-demo.hbs`:
- Around line 26-32: The standalone AkCheckbox in the demo lacks an accessible
name; update the freestyle variant so the checkbox is either wrapped with
AkFormControlLabel (use AkFormControlLabel around the AkCheckbox and supply a
visible label string) or supply an explicit accessible name prop (e.g.,
ariaLabel or label prop passed down) to AkCheckbox; modify the template where
AkCheckbox is rendered (the instance using `@checked`={{this.checked}}
`@indeterminate`={{this.indeterminate}} `@onChange`={{this.handleChange}}) to
include the chosen accessibility fix.
In `@app/components/ak-clipboard/freestyle-section.hbs`:
- Around line 12-15: The hard-coded id 'copy-input' on AkTextField and the
data-clipboard-target:'#copy-input' can produce duplicate DOM IDs; change to a
generated/dynamic id (e.g., create a local uniqueId variable or use an
Ember/utility helper) and use that id for both the AkTextField id and the
AkButton data-clipboard-target (prefixing with '#'), keeping the existing usage
of {{cb.triggerId}} for the button id; update the template to bind the generated
id instead of the literal 'copy-input' so each render instance gets a unique
selector.
In `@app/components/ak-drawer/freestyle-demo.hbs`:
- Line 9: The template uses the {{style}} modifier (in the div with class 'p-4')
which requires the ember-style-modifier addon that isn’t installed; either add
the addon (install ember-style-modifier and add it to package.json) so {{style}}
works across templates, or replace the modifier usage with a plain static style
attribute (e.g., style="width:250px") in the freestyle-demo.hbs and the other
templates (loading.hbs, payment-failure.hbs, etc.) that use {{style}}.
In `@app/components/ak-icon-button/freestyle-section.hbs`:
- Around line 2-36: Several AkIconButton usages render icon-only buttons without
accessible names; update each icon-only example (instances of AkIconButton with
child AkIcon in freestyle-section.hbs) to include an aria-label describing the
action (e.g., "close", "refresh", "delete", "done") so screen readers announce
the purpose; ensure every AkIconButton that has no visible text gets an
appropriate aria-label attribute matching the icon action.
In `@app/components/ak-list/freestyle-demo.ts`:
- Around line 11-18: The Args type in the AkListFreestyleDemoSignature is
missing the optional noGutters property which the template passes; update the
AkListFreestyleDemoSignature interface so its Args includes noGutters?: boolean
to match the template usage (ensure the property is optional and typed boolean)
so Glint template type-checking succeeds.
In `@app/components/ak-menu/freestyle-demo.hbs`:
- Around line 3-5: The icon-only menu trigger lacks an accessible name; update
the AkIconButton used in freestyle-demo.hbs (the element that calls
handleMoreClick) to include an accessible label by adding an aria-label (or
aria-labelledby) and appropriate ARIA state such as aria-haspopup="true" and
aria-expanded bound to the menu open state; ensure the label text clearly
describes the button (e.g., "Open menu") and keep references to AkIconButton and
handleMoreClick when making the change.
In `@app/components/ak-popover/freestyle-section.hbs`:
- Around line 2-4: The example's icon-only trigger lacks an accessible name;
update the FreestyleUsage `@source` so the AkIconButton used as the trigger
provides an explicit aria-label (e.g., "More options") or uses the component's
accepted aria prop so the icon button has an accessible name, keeping the
existing {{on "click" this.handleMoreClick}} handler and AkIcon/AkIconButton
usage intact.
In `@app/components/ak-skeleton/freestyle-section.hbs`:
- Around line 6-8: The AkSkeleton usages in freestyle-section.hbs pass
`@height`='' which can cause unexpected collapse; remove the `@height` attribute on
the three AkSkeleton instances when you want the default height or replace
`@height`='' with an explicit value (e.g., '20px' or another intended height) for
the rectangular/rounded variants so they render predictably; update the three
AkSkeleton tags (the ones with `@width`='250px' and `@tag`='span' and variants
'rectangular'/'rounded') accordingly.
In `@app/components/ak-text-field/freestyle-section.hbs`:
- Around line 9-18: Update the demo copy in the AkTextField examples: change the
helper text strings passed via `@helperText` from "I am an helper text" / "I am an
helper text in error state" to "I am a helper text" / "I am a helper text in
error state", update the label values that currently read "Helper Text" and
"Readonly" to use consistent casing and wording like "Helper text" and "Read
only", and adjust any `@readonly` attribute labels (e.g., "Readonly with value")
to "Read only" phrasing so all visible showcase strings are polished and
consistent.
In `@app/components/ak-toggle/freestyle-demo.hbs`:
- Around line 1-40: The demo hardcodes `@disabled` and `@readonly` as false for
AkToggle and AkFormControlLabel, ignoring incoming args; change every occurrence
to forward the incoming args instead (e.g. replace `@disabled`={{false}} and
`@readonly`={{false}} with `@disabled`={{`@disabled`}} and `@readonly`={{`@readonly`}}),
and ensure the AkFormControlLabel also receives `@disabled`={{`@disabled`}} so
fcl.disabled reflects the passed-in disabled state; keep existing bindings like
`@onChange` (this.handleChange / this.handleSizeChange / this.handleLabelChange)
unchanged.
In `@app/router.ts`:
- Around line 12-14: The freestyle route (this.route('freestyle', ...) /
this.route('component', { path: '/:component_id' })) is currently public; move
it into the existing authenticated route block or gate its registration by
environment. Fix by either relocating the this.route('freestyle', ...)
declaration inside the authenticated route callback (e.g., inside
this.route('authenticated', function() { ... })), or wrap the freestyle route
registration with an environment check (e.g., if (process.env.NODE_ENV !==
'production') { /* register freestyle route */ }) so it only registers in
dev/staging.
In `@app/routes/freestyle.ts`:
- Around line 8-15: The route currently mutates the singleton service directly
and hard-codes values; update activate() to save the existing
emberFreestyle.showCode and emberFreestyle.showLabels into route instance
properties (e.g. this._prevShowCode, this._prevShowLabels), then set both flags
to true; update deactivate() to restore both flags from those saved properties
(this.emberFreestyle.showCode = this._prevShowCode;
this.emberFreestyle.showLabels = this._prevShowLabels) and clear the saved
properties to avoid leaks. Ensure you reference the existing methods activate
and deactivate and the emberFreestyle service properties showCode and
showLabels.
In `@app/styles/_freestyle.scss`:
- Around line 93-97: The .&--active rule uses text color `#1976d2` on background
`#e3f2fd` which fails WCAG AA; update the color in the &--active selector to a
darker blue that achieves a contrast ratio ≥ 4.5 (for example swap `#1976d2` for a
darker shade such as `#0d47a1` or update the relevant variable), and if your
codebase uses a color variable (e.g., a $primary-... or --color-... token)
update that token instead so all references remain consistent; confirm the final
contrast ratio meets WCAG AA for normal text.
In `@app/templates/freestyle/index.hbs`:
- Around line 1-5: The template is bound to the wrong route because it
references this.model (used by the component route) but lives in
freestyle/index.hbs; move or rename this template so it becomes
freestyle/component.hbs (so the route will provide the component_id model), or
alternatively update the route/controller wiring to expose the expected model to
the index route; specifically ensure the {{component (concat (or this.model
'ak-accordion') '/freestyle-section')}} usage inside the FreestyleGuide receives
the route model from the component route (or change the template to read the
correct property exposed by the index route) so component rendering works as
intended.
---
Nitpick comments:
In `@app/components/ak-chip/freestyle-section.hbs`:
- Around line 22-27: The "Deletable" demo uses AkChip with `@button`={{true}}
which only makes chips clickable, causing mismatch with the title; either rename
the FreestyleUsage title from 'Deletable' to 'Clickable' or 'Button Chips', or
update the AkChip examples to demonstrate actual delete behavior by adding an
`@onDelete` handler to each <AkChip> (and optionally keep `@button` if both
behaviours are supported) so the section label matches the implemented
interactivity; look for the FreestyleUsage block and AkChip components in this
snippet to apply the change.
In `@app/components/ak-icon-button/freestyle-section.hbs`:
- Around line 5-8: The AkIcon components are passing `@color`='' which relies on
an empty string as falsy; remove the `@color`='' attribute from the AkIcon tags
(e.g., the AkIcon instances nested in AkIconButton with `@iconName`='close' and
`@iconName`='refresh') so the prop is omitted and the component falls back to the
intended default (inherit) that matches the AkIconColorVariant type.
In `@app/components/ak-list/freestyle-demo.hbs`:
- Around line 5-11: The template hardcodes `@noGutters`={{false}} on the
akl.listItem invocation; change it to forward the incoming arg by replacing the
hardcoded value with `@noGutters`={{`@noGutters`}} so the freestyle-demo can
demonstrate different gutter configurations—update the akl.listItem invocation
in the freestyle-demo.hbs to use the `@noGutters` arg passed into the component.
In `@app/components/ak-pagination/freestyle-demo.hbs`:
- Line 5: The template currently hardcodes `@totalItems`={{50}} which diverges
from the actual dataset; remove the literal and derive totalItems from the
backing dataset (TOTAL_DATA) instead — either pass TOTAL_DATA.length directly
into the template (e.g. `@totalItems`={{TOTAL_DATA.length}}) or compute a
getter/property (e.g. totalItems) in the freestyle-demo component/controller
that returns TOTAL_DATA.length and reference that property in the template
(replace `@totalItems` with `@totalItems`={{this.totalItems}}); ensure any code that
uses `@totalItems` (pagination component) continues to receive the dynamic value.
In `@app/components/ak-pagination/freestyle-demo.ts`:
- Around line 16-32: The three actions onItemPerPageChange, nextAction, and
prevAction duplicate setting this.limit and this.offset; extract a single helper
method (e.g., updatePagination or setPagination) that accepts { limit, offset }
and performs the assignments, then have each action call that helper instead of
repeating the two assignments so future pagination logic is centralized.
In `@app/components/ak-select/freestyle-demo.ts`:
- Line 13: DEFAULT_ITEM is initialized with SELECT_ITEMS[0]! using a no-op
non-null assertion; remove the trailing "!" so the initializer reads
SELECT_ITEMS[0] and let the declared type SelectItem handle typing. Update the
declaration of DEFAULT_ITEM (symbol DEFAULT_ITEM) to use SELECT_ITEMS[0] without
"!" to eliminate the unnecessary assertion.
In `@app/components/ak-tabs/freestyle-demo.hbs`:
- Line 16: The inline style on AkIcon using "!important" should be removed;
instead, create a CSS rule (e.g., .ak-icon--large or a contextual selector in
the freestyle-demo component stylesheet) that sets font-size: 1.29rem with
appropriate specificity, then replace the inline {{style ...}} usage in the
template by adding that class to the AkIcon invocation (AkIcon
`@iconName`={{item.iconName}} class="ak-icon--large" or the equivalent
class-binding in the template) so styling is controlled via stylesheet rather
than an inline !important.
In `@app/components/ak-toggle/freestyle-demo.ts`:
- Around line 28-32: The handler handleSizeChange currently treats any
non-'small'/'medium' value as 'large', which can mask bad inputs; update
handleSizeChange to explicitly check for size === 'large' and set checkedLarge
only in that branch, and for any other unexpected size either ignore the call
(no state change) or throw/assert (e.g. throw new Error or console.warn) so
invalid values are not silently mapped to checkedLarge; reference the properties
checkedSmall, checkedMedium, and checkedLarge when implementing the explicit
branches.
In `@app/components/ak-tree/freestyle-demo.ts`:
- Around line 10-18: The TREE_DATA entry for the node with key 'Child1.1'
currently includes expanded: true which conflicts with or misleads about the
component-controlled expansion state held in the `@tracked` expanded array
(initialized to ['Root1', 'Root2']); either remove the expanded property from
the static TREE_DATA node or add a brief comment next to the 'Child1.1' node
explaining it is unused by AkTree and kept only for illustrative/legacy purposes
so readers aren’t confused by the component’s actual expansion source.
- Around line 37-39: Document the magic multiplier used in calculatePadding: add
a short explanatory comment above calculatePadding (or extract 0.9286 into a
well-named constant like PADDING_SCALE) that explains why 0.9286 is used (e.g.,
alignment with the design system's spacing scale or conversion from pixel
values), reference the calculatePadding(treeDepth: number) function and ensure
the comment mentions the expected units (em) and any source or formula for the
value so future maintainers understand and can update it safely.
In `@app/components/freestyle-component-renderer.hbs`:
- Around line 1-66: The template's long else-if ladder (checking `@componentId`
and rendering AkX::FreestyleSection) should be replaced by a TS registry and
dynamic lookup: create a lightweight module (e.g.,
freestyle-component-registry.ts) that exports a map from componentId strings
(like "ak-accordion") to the corresponding component reference/name (the same
values currently used in the template, e.g., "AkAccordion::FreestyleSection");
update the component backing class for this template
(FreestyleComponentRenderer) to import that registry and expose a
computed/derived property (e.g., selectedComponent) that returns
registry[this.args.componentId] or null; then simplify the HBS to render
dynamically via the component helper (e.g., {{`#if`
this.selectedComponent}}{{component this.selectedComponent}}{{else}}<p
class='text-secondary'>Component not found: {{`@componentId`}}</p>{{/if}}). This
moves the registry out of freestyle-component-renderer.hbs into a single source
of truth and uses `@componentId`, FreestyleComponentRenderer, selectedComponent,
and the component helper for the dynamic lookup.
In `@app/components/freestyle-nav.ts`:
- Around line 3-35: The COMPONENTS array lacks explicit TypeScript types; define
a small interface or type (e.g., ComponentItem with id: string and label:
string) and annotate COMPONENTS as ComponentItem[] (or readonly ComponentItem[]
if immutable) so each entry (the objects in COMPONENTS) is type-checked; update
any exports/usages of COMPONENTS to use the new type for better autocomplete and
compile-time safety.
In `@app/components/freestyle-section.ts`:
- Around line 3-6: The show getter in class FreestyleSection is intended to
override the base class member from FreestyleSectionAddon; add the TypeScript
override modifier to the getter (i.e., declare `override get show(): boolean`)
in the FreestyleSection class to make the override explicit and consistent with
TS best practices.
In `@app/components/freestyle-usage.ts`:
- Around line 3-6: The show getter in class FreestyleUsage lacks the override
keyword while other inherited getters (e.g., hasCode) use it; update the show
getter in FreestyleUsage to include the override modifier (i.e., change the
declaration of the show getter in FreestyleUsage to explicitly use override) so
the intent is clear and consistent with hasCode.
In `@app/routes/freestyle/component.ts`:
- Around line 38-40: The model function currently silently maps invalid slugs to
'ak-accordion'; update model(params: { component_id?: string }) to detect when
params.component_id is not in VALID_COMPONENTS and then perform a canonical
redirect to the default route (e.g. redirect to '/freestyle/ak-accordion') or
return a proper not-found response (e.g. throw a 404 Response) instead of
returning 'ak-accordion'. Use the same VALID_COMPONENTS check to decide and
invoke your framework's redirect/response mechanism from within model rather
than silently substituting the id.
In `@app/styles/_freestyle.scss`:
- Around line 1-8: Add a short explanatory comment above the rules indicating
the use of !important is intentional to override ember-freestyle defaults, so
future maintainers won't remove it; reference the selector block
(.FreestyleGuide-header, .FreestyleGuide-cta, .FreestyleGuide-nav,
.FreestyleGuide-aside) and state that we hide the built-in header/sidebar in
favor of our own sidebar and therefore need the !important overrides.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 078e2bc5-f72b-46cd-b2f4-cf37ab00728f
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (81)
app/components/ak-accordion/freestyle-section.hbsapp/components/ak-appbar/freestyle-section.hbsapp/components/ak-autocomplete/freestyle-demo.hbsapp/components/ak-autocomplete/freestyle-demo.tsapp/components/ak-autocomplete/freestyle-section.hbsapp/components/ak-button/freestyle-section.hbsapp/components/ak-checkbox-tree/freestyle-demo.hbsapp/components/ak-checkbox-tree/freestyle-demo.tsapp/components/ak-checkbox-tree/freestyle-section.hbsapp/components/ak-checkbox/freestyle-demo.hbsapp/components/ak-checkbox/freestyle-demo.tsapp/components/ak-checkbox/freestyle-section.hbsapp/components/ak-chip/freestyle-section.hbsapp/components/ak-clipboard/freestyle-section.hbsapp/components/ak-date-picker/freestyle-demo.hbsapp/components/ak-date-picker/freestyle-demo.tsapp/components/ak-date-picker/freestyle-section.hbsapp/components/ak-divider/freestyle-section.hbsapp/components/ak-drawer/freestyle-demo.hbsapp/components/ak-drawer/freestyle-demo.tsapp/components/ak-drawer/freestyle-section.hbsapp/components/ak-icon-button/freestyle-section.hbsapp/components/ak-icon/freestyle-section.hbsapp/components/ak-link/freestyle-section.hbsapp/components/ak-list/freestyle-demo.hbsapp/components/ak-list/freestyle-demo.tsapp/components/ak-list/freestyle-section.hbsapp/components/ak-loader/freestyle-section.hbsapp/components/ak-menu/freestyle-demo.hbsapp/components/ak-menu/freestyle-demo.tsapp/components/ak-menu/freestyle-section.hbsapp/components/ak-modal/freestyle-demo.hbsapp/components/ak-modal/freestyle-demo.tsapp/components/ak-modal/freestyle-section.hbsapp/components/ak-pagination/freestyle-demo.hbsapp/components/ak-pagination/freestyle-demo.tsapp/components/ak-pagination/freestyle-section.hbsapp/components/ak-popover/freestyle-demo.hbsapp/components/ak-popover/freestyle-demo.tsapp/components/ak-popover/freestyle-section.hbsapp/components/ak-radio/freestyle-section.hbsapp/components/ak-select/freestyle-demo.hbsapp/components/ak-select/freestyle-demo.tsapp/components/ak-select/freestyle-section.hbsapp/components/ak-skeleton/freestyle-section.hbsapp/components/ak-stack/freestyle-section.hbsapp/components/ak-table/freestyle-demo.hbsapp/components/ak-table/freestyle-demo.tsapp/components/ak-table/freestyle-section.hbsapp/components/ak-tabs/freestyle-demo.hbsapp/components/ak-tabs/freestyle-demo.tsapp/components/ak-tabs/freestyle-section.hbsapp/components/ak-text-field/freestyle-section.hbsapp/components/ak-toggle/freestyle-demo.hbsapp/components/ak-toggle/freestyle-demo.tsapp/components/ak-toggle/freestyle-section.hbsapp/components/ak-tooltip/freestyle-section.hbsapp/components/ak-tree/freestyle-demo.hbsapp/components/ak-tree/freestyle-demo.tsapp/components/ak-tree/freestyle-section.hbsapp/components/ak-typography/freestyle-section.hbsapp/components/freestyle-component-renderer.hbsapp/components/freestyle-component-renderer.tsapp/components/freestyle-nav.hbsapp/components/freestyle-nav.tsapp/components/freestyle-section.hbsapp/components/freestyle-section.tsapp/components/freestyle-usage.hbsapp/components/freestyle-usage.tsapp/controllers/freestyle/component.tsapp/controllers/freestyle/index.tsapp/router.tsapp/routes/freestyle.tsapp/routes/freestyle/component.tsapp/routes/freestyle/index.tsapp/styles/_freestyle.scssapp/styles/app.scssapp/templates/freestyle.hbsapp/templates/freestyle/component.hbsapp/templates/freestyle/index.hbspackage.json
| <AkTypography @variant='h5' @color='inherit'>Appbar title</AkTypography> | ||
| <AkIconButton class={{ab.classes.defaultIconBtn}}> | ||
| <AkIcon @iconName='close' /> | ||
| </AkIconButton> |
There was a problem hiding this comment.
Label the close action for screen readers.
The trailing icon button is icon-only, so it needs an accessible name such as aria-label='Close'.
♿ Suggested fix
- <AkIconButton class={{ab.classes.defaultIconBtn}}>
+ <AkIconButton class={{ab.classes.defaultIconBtn}} aria-label='Close'>
<AkIcon `@iconName`='close' />
</AkIconButton>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <AkTypography @variant='h5' @color='inherit'>Appbar title</AkTypography> | |
| <AkIconButton class={{ab.classes.defaultIconBtn}}> | |
| <AkIcon @iconName='close' /> | |
| </AkIconButton> | |
| <AkTypography `@variant`='h5' `@color`='inherit'>Appbar title</AkTypography> | |
| <AkIconButton class={{ab.classes.defaultIconBtn}} aria-label='Close'> | |
| <AkIcon `@iconName`='close' /> | |
| </AkIconButton> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-appbar/freestyle-section.hbs` around lines 15 - 18, The
trailing icon-only button (AkIconButton in freestyle-section.hbs) lacks an
accessible name; add an aria-label (e.g., aria-label="Close") to the
AkIconButton element so screen readers announce the action—ensure the attribute
is set on the AkIconButton component (not just AkIcon) to provide the accessible
name.
| <AkCheckbox | ||
| @checked={{this.checked}} | ||
| @indeterminate={{this.indeterminate}} | ||
| @disabled={{false}} | ||
| @readonly={{false}} | ||
| @onChange={{this.handleChange}} | ||
| /> |
There was a problem hiding this comment.
Give the standalone checkbox an accessible name.
The default branch renders a bare checkbox with no associated label, so assistive tech users get an unlabeled control. Wrap this variant in AkFormControlLabel or pass an explicit accessible name through to the underlying input.
♿ Suggested fix
{{else}}
- <AkCheckbox
- `@checked`={{this.checked}}
- `@indeterminate`={{this.indeterminate}}
- `@disabled`={{false}}
- `@readonly`={{false}}
- `@onChange`={{this.handleChange}}
- />
+ <AkFormControlLabel `@label`='Check me'>
+ <AkCheckbox
+ `@checked`={{this.checked}}
+ `@indeterminate`={{this.indeterminate}}
+ `@disabled`={{false}}
+ `@readonly`={{false}}
+ `@onChange`={{this.handleChange}}
+ />
+ </AkFormControlLabel>
{{/if}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <AkCheckbox | |
| @checked={{this.checked}} | |
| @indeterminate={{this.indeterminate}} | |
| @disabled={{false}} | |
| @readonly={{false}} | |
| @onChange={{this.handleChange}} | |
| /> | |
| {{else}} | |
| <AkFormControlLabel `@label`='Check me'> | |
| <AkCheckbox | |
| `@checked`={{this.checked}} | |
| `@indeterminate`={{this.indeterminate}} | |
| `@disabled`={{false}} | |
| `@readonly`={{false}} | |
| `@onChange`={{this.handleChange}} | |
| /> | |
| </AkFormControlLabel> | |
| {{/if}} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-checkbox/freestyle-demo.hbs` around lines 26 - 32, The
standalone AkCheckbox in the demo lacks an accessible name; update the freestyle
variant so the checkbox is either wrapped with AkFormControlLabel (use
AkFormControlLabel around the AkCheckbox and supply a visible label string) or
supply an explicit accessible name prop (e.g., ariaLabel or label prop passed
down) to AkCheckbox; modify the template where AkCheckbox is rendered (the
instance using `@checked`={{this.checked}} `@indeterminate`={{this.indeterminate}}
`@onChange`={{this.handleChange}}) to include the chosen accessibility fix.
| <AkTextField id='copy-input' @value='I will be copied!' /> | ||
| <AkClipboard as |cb|> | ||
| <AkButton class='mt-2' data-clipboard-target='#copy-input' id={{cb.triggerId}}> | ||
| Copy Input text |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect how AkTextField applies incoming id attributes and where the real input lives.
fd 'ak-text-field' app/components | while read -r file; do
case "$file" in
*.hbs|*.ts|*.gts)
echo "== $file =="
rg -n -C2 '(<input|@id|inputId|id=|\.{3}attributes)' "$file"
;;
esac
doneRepository: appknox/irene
Length of output: 39
🏁 Script executed:
# First, let's understand the component directory structure
fd --type f -e ts -e gts -e hbs app/components | head -20Repository: appknox/irene
Length of output: 418
🏁 Script executed:
# Search for AkTextField definition more broadly
rg 'AkTextField|ak-text-field' app/components --type ts --type gts --type hbs -lRepository: appknox/irene
Length of output: 84
🏁 Script executed:
# Also check for text field components with different naming
fd 'text.*field|field.*text' app/components --type fRepository: appknox/irene
Length of output: 39
🏁 Script executed:
# Fix the fd syntax and explore the components directory
fd . app/components --type f | grep -i text | head -20Repository: appknox/irene
Length of output: 1575
🏁 Script executed:
# Search for AkTextField component definition across codebase
rg 'AkTextField' --type ts --type hbs -lRepository: appknox/irene
Length of output: 4395
🏁 Script executed:
# Read the freestyle-section.hbs file directly to see imports and component usage
cat -n app/components/ak-clipboard/freestyle-section.hbsRepository: appknox/irene
Length of output: 910
🏁 Script executed:
# Read the AkTextField component implementation
cat -n app/components/ak-text-field/index.tsRepository: appknox/irene
Length of output: 1531
🏁 Script executed:
# Check if there's a template file for AkTextField
fd . app/components/ak-text-field --type fRepository: appknox/irene
Length of output: 270
🏁 Script executed:
# Read the AkTextField template to see where id is applied
cat -n app/components/ak-text-field/index.hbsRepository: appknox/irene
Length of output: 2461
Consider using a dynamic ID or ref to avoid duplicate IDs in the demo.
The id='copy-input' is hard-coded and will cause duplicate DOM IDs if this freestyle section is ever rendered multiple times. While AkTextField correctly forwards the id to its internal <Input> element (so the selector works), it would be more robust to use a dynamic or generated ID for this example.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-clipboard/freestyle-section.hbs` around lines 12 - 15, The
hard-coded id 'copy-input' on AkTextField and the
data-clipboard-target:'#copy-input' can produce duplicate DOM IDs; change to a
generated/dynamic id (e.g., create a local uniqueId variable or use an
Ember/utility helper) and use that id for both the AkTextField id and the
AkButton data-clipboard-target (prefixing with '#'), keeping the existing usage
of {{cb.triggerId}} for the button id; update the template to bind the generated
id instead of the literal 'copy-input' so each render instance gets a unique
selector.
| @disableBackdropClick={{false}} | ||
| @onClose={{this.handleClose}} | ||
| > | ||
| <div class='p-4' {{style width='250px'}}> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n-- dependency check --\n'
rg -n '"ember-style-modifier"|"style-modifier"|".*styled.*modifier.*"' package.json || true
printf '\n-- local style helper/modifier candidates --\n'
fd '^style\.(ts|js)$' app/modifiers app/helpers lib 2>/dev/null || true
rg -n "export default .*modifier|modifier\\(" app/modifiers lib 2>/dev/null || true
rg -n "export default .*helper|helper\\(" app/helpers lib 2>/dev/null || trueRepository: appknox/irene
Length of output: 1834
🏁 Script executed:
# Check if {{style is used elsewhere in templates
rg -n "{{style" app/ --type hbs || true
# Check package.json for all dependencies to see if any might provide style
rg -n '"dependencies"|"devDependencies"' package.json -A 50 | head -100 || true
# Check if there are any addon imports or registrations in app
rg -n "ember-style-modifier|@ember|style.*modifier" app/ --type ts --type js | head -20 || trueRepository: appknox/irene
Length of output: 4835
🏁 Script executed:
# Read the freestyle-demo.hbs file
cat -n app/components/ak-drawer/freestyle-demo.hbs
# Search for style usage in templates with proper escaping
rg 'style' app/ --type hbs -n | grep -i 'style.*=' | head -20Repository: appknox/irene
Length of output: 2510
🏁 Script executed:
# Check if there's a style modifier in app/modifiers
ls -la app/modifiers/
# Check if `@ember/render-modifiers` provides style modifier
rg -n "export.*style|style.*export" app/ --type ts --type js | head -10
# Check for any modifiers index or re-exports
cat -n app/modifiers/index.ts 2>/dev/null || echo "No modifiers/index.ts"
# Search for where style modifier might be defined
rg -n "style.*modifier|modifier.*style" . --type ts --type js --type hbs | head -20Repository: appknox/irene
Length of output: 1552
🏁 Script executed:
# Check ember-cli-build.js for addon setup
cat -n ember-cli-build.js | head -50
# Check if there's an ember.json or app config
cat -n .ember.json 2>/dev/null || cat -n ember.json 2>/dev/null || echo "No ember config found"
# Check package.json for ember-freestyle
rg -n "ember-freestyle" package.json
# Search for any documentation or imports of style modifier in the app
rg -n "import.*style|from.*style" app/ --type ts --type js --type hbs | head -10
# Check Ember version to see if style is built-in
rg -n '"ember-source"|"ember"' package.json | head -5Repository: appknox/irene
Length of output: 2832
🌐 Web query:
Ember 5.12 style modifier built-in template helper
💡 Result:
Ember 5.12 does not include a built-in {{style}} template helper/element modifier. Ember’s only built-in element modifier is {{on}} (for event listeners). [1], [2]
If you want {{style ...}} behavior, it typically comes from the ember-style-modifier addon, which “provides a {{style}} element modifier to set element’s style.” [3]
Sources: [1] [2] [3]
🌐 Web query:
ember-freestyle provides style modifier
💡 Result:
ember-freestyle does not provide a {{style}} element modifier—it’s a component explorer / living style guide addon. [1]
If you’re looking for a {{style}} modifier, use ember-style-modifier, which explicitly provides a {{style}} element modifier for setting inline styles safely. [2]
Install
ember install ember-style-modifierUse
Sources: ember-freestyle package overview [1]; ember-style-modifier README/description [2].
Install ember-style-modifier addon or use plain style attribute instead.
Line 9 uses {{style width='250px'}}, but this requires the ember-style-modifier addon which is not listed in package.json. Ember 5.12 has no built-in {{style}} modifier. Either add the addon with ember install ember-style-modifier or use a static style attribute.
Fallback using plain style attribute
- <div class='p-4' {{style width='250px'}}>
+ <div class='p-4' style='width: 250px;'>Note: This pattern is used in 8+ other templates (loading.hbs, payment-failure.hbs, etc.), suggesting the addon should be added to resolve issues across the codebase.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div class='p-4' {{style width='250px'}}> | |
| <div class='p-4' style='width: 250px;'> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-drawer/freestyle-demo.hbs` at line 9, The template uses the
{{style}} modifier (in the div with class 'p-4') which requires the
ember-style-modifier addon that isn’t installed; either add the addon (install
ember-style-modifier and add it to package.json) so {{style}} works across
templates, or replace the modifier usage with a plain static style attribute
(e.g., style="width:250px") in the freestyle-demo.hbs and the other templates
(loading.hbs, payment-failure.hbs, etc.) that use {{style}}.
| <FreestyleUsage @slug='ak-icon-button-default' @title='Default'> | ||
| <AkTypography @color='textSecondary' @gutterBottom={{true}}>Experiment with me</AkTypography> | ||
| <AkIconButton @type='button' @size='medium' disabled={{false}}> | ||
| <AkIcon @color='' @iconName='close' /> | ||
| </AkIconButton> | ||
| <AkIconButton @type='button' @variant='outlined' @size='medium' disabled={{false}}> | ||
| <AkIcon @color='' @iconName='refresh' /> | ||
| </AkIconButton> | ||
| </FreestyleUsage> | ||
|
|
||
| <FreestyleUsage @slug='ak-icon-button-variants' @title='Variants'> | ||
| <AkIconButton><AkIcon @iconName='delete' /></AkIconButton> | ||
| <AkIconButton @variant='outlined'><AkIcon @iconName='refresh' /></AkIconButton> | ||
| </FreestyleUsage> | ||
|
|
||
| <FreestyleUsage @slug='ak-icon-button-sizes' @title='Sizes'> | ||
| <AkIconButton @size='small'><AkIcon @iconName='delete' /></AkIconButton> | ||
| <AkIconButton><AkIcon @iconName='delete' /></AkIconButton> | ||
| <AkIconButton @variant='outlined' @size='small'><AkIcon @iconName='delete' /></AkIconButton> | ||
| <AkIconButton @variant='outlined'><AkIcon @iconName='delete' /></AkIconButton> | ||
| </FreestyleUsage> | ||
|
|
||
| <FreestyleUsage @slug='ak-icon-button-disabled' @title='Disabled'> | ||
| <AkIconButton disabled={{true}}><AkIcon @iconName='delete' /></AkIconButton> | ||
| <AkIconButton disabled={{true}} @variant='outlined'><AkIcon @iconName='refresh' /></AkIconButton> | ||
| </FreestyleUsage> | ||
|
|
||
| <FreestyleUsage @slug='ak-icon-button-colors' @title='Colors'> | ||
| <AkIconButton><AkIcon @iconName='refresh' /></AkIconButton> | ||
| <AkIconButton><AkIcon @color='success' @iconName='done' /></AkIconButton> | ||
| <AkIconButton><AkIcon @color='error' @iconName='delete' /></AkIconButton> | ||
| <AkIconButton @variant='outlined'><AkIcon @iconName='refresh' /></AkIconButton> | ||
| <AkIconButton @variant='outlined'><AkIcon @color='success' @iconName='done' /></AkIconButton> | ||
| <AkIconButton @variant='outlined' @color='danger'><AkIcon @color='error' @iconName='delete' /></AkIconButton> | ||
| </FreestyleUsage> |
There was a problem hiding this comment.
Add accessible names to the icon-only buttons.
Every example here renders a clickable icon without a text alternative, so assistive tech will announce unlabeled buttons. Please pass an aria-label that matches the action on each example.
♿ Suggested fix
- <AkIconButton `@type`='button' `@size`='medium' disabled={{false}}>
+ <AkIconButton `@type`='button' `@size`='medium' aria-label='Close' disabled={{false}}>
<AkIcon `@iconName`='close' />
</AkIconButton>
- <AkIconButton `@type`='button' `@variant`='outlined' `@size`='medium' disabled={{false}}>
+ <AkIconButton `@type`='button' `@variant`='outlined' `@size`='medium' aria-label='Refresh' disabled={{false}}>
<AkIcon `@iconName`='refresh' />
</AkIconButton>Apply the same pattern to the delete/done examples below.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-icon-button/freestyle-section.hbs` around lines 2 - 36,
Several AkIconButton usages render icon-only buttons without accessible names;
update each icon-only example (instances of AkIconButton with child AkIcon in
freestyle-section.hbs) to include an aria-label describing the action (e.g.,
"close", "refresh", "delete", "done") so screen readers announce the purpose;
ensure every AkIconButton that has no visible text gets an appropriate
aria-label attribute matching the icon action.
| {{#if (eq @variant 'label')}} | ||
| <AkFormControlLabel @label='Check me' @disabled={{false}} as |fcl|> | ||
| <AkToggle | ||
| @checked={{this.checkedLabel}} | ||
| @size='small' | ||
| @disabled={{fcl.disabled}} | ||
| @readonly={{false}} | ||
| @onChange={{this.handleLabelChange}} | ||
| /> | ||
| </AkFormControlLabel> | ||
| {{else if (eq @variant 'sizes')}} | ||
| <AkToggle | ||
| @checked={{this.checkedSmall}} | ||
| @size='small' | ||
| @disabled={{false}} | ||
| @readonly={{false}} | ||
| @onChange={{fn this.handleSizeChange 'small'}} | ||
| /> | ||
| <AkToggle | ||
| @checked={{this.checkedMedium}} | ||
| @size='medium' | ||
| @disabled={{false}} | ||
| @readonly={{false}} | ||
| @onChange={{fn this.handleSizeChange 'medium'}} | ||
| /> | ||
| <AkToggle | ||
| @checked={{this.checkedLarge}} | ||
| @size='large' | ||
| @disabled={{false}} | ||
| @readonly={{false}} | ||
| @onChange={{fn this.handleSizeChange 'large'}} | ||
| /> | ||
| {{else}} | ||
| <AkToggle | ||
| @checked={{this.checked}} | ||
| @size='small' | ||
| @disabled={{false}} | ||
| @readonly={{false}} | ||
| @onChange={{this.handleChange}} | ||
| /> |
There was a problem hiding this comment.
Forward @disabled and @readonly instead of hardcoding false.
Every branch ignores the incoming args, so disabled/readonly freestyle usages will still render interactive toggles. That breaks the showcase states this demo is supposed to cover.
🐛 Proposed fix
{{`#if` (eq `@variant` 'label')}}
- <AkFormControlLabel `@label`='Check me' `@disabled`={{false}} as |fcl|>
+ <AkFormControlLabel `@label`='Check me' `@disabled`={{`@disabled`}} as |fcl|>
<AkToggle
`@checked`={{this.checkedLabel}}
`@size`='small'
`@disabled`={{fcl.disabled}}
- `@readonly`={{false}}
+ `@readonly`={{`@readonly`}}
`@onChange`={{this.handleLabelChange}}
/>
</AkFormControlLabel>
{{else if (eq `@variant` 'sizes')}}
<AkToggle
`@checked`={{this.checkedSmall}}
`@size`='small'
- `@disabled`={{false}}
- `@readonly`={{false}}
+ `@disabled`={{`@disabled`}}
+ `@readonly`={{`@readonly`}}
`@onChange`={{fn this.handleSizeChange 'small'}}
/>
<AkToggle
`@checked`={{this.checkedMedium}}
`@size`='medium'
- `@disabled`={{false}}
- `@readonly`={{false}}
+ `@disabled`={{`@disabled`}}
+ `@readonly`={{`@readonly`}}
`@onChange`={{fn this.handleSizeChange 'medium'}}
/>
<AkToggle
`@checked`={{this.checkedLarge}}
`@size`='large'
- `@disabled`={{false}}
- `@readonly`={{false}}
+ `@disabled`={{`@disabled`}}
+ `@readonly`={{`@readonly`}}
`@onChange`={{fn this.handleSizeChange 'large'}}
/>
{{else}}
<AkToggle
`@checked`={{this.checked}}
`@size`='small'
- `@disabled`={{false}}
- `@readonly`={{false}}
+ `@disabled`={{`@disabled`}}
+ `@readonly`={{`@readonly`}}
`@onChange`={{this.handleChange}}
/>
{{/if}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {{#if (eq @variant 'label')}} | |
| <AkFormControlLabel @label='Check me' @disabled={{false}} as |fcl|> | |
| <AkToggle | |
| @checked={{this.checkedLabel}} | |
| @size='small' | |
| @disabled={{fcl.disabled}} | |
| @readonly={{false}} | |
| @onChange={{this.handleLabelChange}} | |
| /> | |
| </AkFormControlLabel> | |
| {{else if (eq @variant 'sizes')}} | |
| <AkToggle | |
| @checked={{this.checkedSmall}} | |
| @size='small' | |
| @disabled={{false}} | |
| @readonly={{false}} | |
| @onChange={{fn this.handleSizeChange 'small'}} | |
| /> | |
| <AkToggle | |
| @checked={{this.checkedMedium}} | |
| @size='medium' | |
| @disabled={{false}} | |
| @readonly={{false}} | |
| @onChange={{fn this.handleSizeChange 'medium'}} | |
| /> | |
| <AkToggle | |
| @checked={{this.checkedLarge}} | |
| @size='large' | |
| @disabled={{false}} | |
| @readonly={{false}} | |
| @onChange={{fn this.handleSizeChange 'large'}} | |
| /> | |
| {{else}} | |
| <AkToggle | |
| @checked={{this.checked}} | |
| @size='small' | |
| @disabled={{false}} | |
| @readonly={{false}} | |
| @onChange={{this.handleChange}} | |
| /> | |
| {{`#if` (eq `@variant` 'label')}} | |
| <AkFormControlLabel `@label`='Check me' `@disabled`={{`@disabled`}} as |fcl|> | |
| <AkToggle | |
| `@checked`={{this.checkedLabel}} | |
| `@size`='small' | |
| `@disabled`={{fcl.disabled}} | |
| `@readonly`={{`@readonly`}} | |
| `@onChange`={{this.handleLabelChange}} | |
| /> | |
| </AkFormControlLabel> | |
| {{else if (eq `@variant` 'sizes')}} | |
| <AkToggle | |
| `@checked`={{this.checkedSmall}} | |
| `@size`='small' | |
| `@disabled`={{`@disabled`}} | |
| `@readonly`={{`@readonly`}} | |
| `@onChange`={{fn this.handleSizeChange 'small'}} | |
| /> | |
| <AkToggle | |
| `@checked`={{this.checkedMedium}} | |
| `@size`='medium' | |
| `@disabled`={{`@disabled`}} | |
| `@readonly`={{`@readonly`}} | |
| `@onChange`={{fn this.handleSizeChange 'medium'}} | |
| /> | |
| <AkToggle | |
| `@checked`={{this.checkedLarge}} | |
| `@size`='large' | |
| `@disabled`={{`@disabled`}} | |
| `@readonly`={{`@readonly`}} | |
| `@onChange`={{fn this.handleSizeChange 'large'}} | |
| /> | |
| {{else}} | |
| <AkToggle | |
| `@checked`={{this.checked}} | |
| `@size`='small' | |
| `@disabled`={{`@disabled`}} | |
| `@readonly`={{`@readonly`}} | |
| `@onChange`={{this.handleChange}} | |
| /> | |
| {{/if}} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/ak-toggle/freestyle-demo.hbs` around lines 1 - 40, The demo
hardcodes `@disabled` and `@readonly` as false for AkToggle and AkFormControlLabel,
ignoring incoming args; change every occurrence to forward the incoming args
instead (e.g. replace `@disabled`={{false}} and `@readonly`={{false}} with
`@disabled`={{`@disabled`}} and `@readonly`={{`@readonly`}}), and ensure the
AkFormControlLabel also receives `@disabled`={{`@disabled`}} so fcl.disabled
reflects the passed-in disabled state; keep existing bindings like `@onChange`
(this.handleChange / this.handleSizeChange / this.handleLabelChange) unchanged.
| this.route('freestyle', function () { | ||
| this.route('component', { path: '/:component_id' }); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there's any route-level protection or environment gating for freestyle
rg -n 'freestyle' --type ts -g '!*.d.ts' app/routes/Repository: appknox/irene
Length of output: 268
🏁 Script executed:
# View the app/router.ts file to understand the full structure
head -40 app/router.ts | cat -nRepository: appknox/irene
Length of output: 1259
🏁 Script executed:
# Check the freestyle route handler for any authentication guards
cat -n app/routes/freestyle.tsRepository: appknox/irene
Length of output: 644
🏁 Script executed:
# Search for authentication middleware or route guards
rg -n 'authenticated|protect|auth|requireLogin' app/router.ts -A 3Repository: appknox/irene
Length of output: 204
🏁 Script executed:
# Check the application route for guards
cat -n app/routes/application.ts 2>/dev/null | head -30Repository: appknox/irene
Length of output: 1363
🏁 Script executed:
# Check if ember-freestyle is a devDependency
grep -A 2 -B 2 "ember-freestyle" package.jsonRepository: appknox/irene
Length of output: 327
🏁 Script executed:
# Check if there's environment-based configuration for freestyle route
rg -n 'environment|development|production' app/router.ts -B 2 -A 2Repository: appknox/irene
Length of output: 221
🏁 Script executed:
# Find the authenticated route to check if it has guards
rg -n "class.*Authenticated.*Route" app/routes/ -A 20Repository: appknox/irene
Length of output: 50370
🏁 Script executed:
# Also check if there's a specific authenticated.ts route file
cat -n app/routes/authenticated.ts 2>/dev/null | head -40Repository: appknox/irene
Length of output: 2250
🏁 Script executed:
# Check ember-freestyle documentation or usage patterns in the codebase
rg -n "ember-freestyle" --type ts -B 3 -A 3Repository: appknox/irene
Length of output: 1302
Move the freestyle route into the authenticated block or environment-gate it.
The freestyle route is publicly accessible without authentication. If this is an internal documentation/component library tool, it should either be:
- Moved inside the
authenticatedroute block, or - Conditionally registered only in development/staging environments.
Currently, anyone can access the route without logging in.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/router.ts` around lines 12 - 14, The freestyle route
(this.route('freestyle', ...) / this.route('component', { path: '/:component_id'
})) is currently public; move it into the existing authenticated route block or
gate its registration by environment. Fix by either relocating the
this.route('freestyle', ...) declaration inside the authenticated route callback
(e.g., inside this.route('authenticated', function() { ... })), or wrap the
freestyle route registration with an environment check (e.g., if
(process.env.NODE_ENV !== 'production') { /* register freestyle route */ }) so
it only registers in dev/staging.
| activate() { | ||
| this.emberFreestyle.showCode = true; | ||
| this.emberFreestyle.showLabels = true; | ||
| } | ||
|
|
||
| deactivate() { | ||
| this.emberFreestyle.showCode = true; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify where these flags are mutated today.
rg -n -C2 'show(Code|Labels)\s*=' appRepository: appknox/irene
Length of output: 492
🏁 Script executed:
#!/bin/bash
# Find the EmberFreestyleService definition
fd -e ts -e js | xargs grep -l "EmberFreestyleService" | head -20Repository: appknox/irene
Length of output: 164
🏁 Script executed:
#!/bin/bash
# Check for any tests related to FreestyleRoute
fd -e ts -e js -path "*/test*" -o -path "*/.test.*" | xargs grep -l "FreestyleRoute" 2>/dev/null | head -10Repository: appknox/irene
Length of output: 225
🏁 Script executed:
#!/bin/bash
# Look at the full FreestyleRoute file to understand context
cat -n app/routes/freestyle.tsRepository: appknox/irene
Length of output: 644
🏁 Script executed:
#!/bin/bash
# Search for any service definitions or configurations
rg -n "ember-freestyle" app --type ts --type js -A 3 -B 3Repository: appknox/irene
Length of output: 1302
🏁 Script executed:
#!/bin/bash
# Search for tests related to FreestyleRoute across all test directories
find . -type f \( -name "*.test.ts" -o -name "*.spec.ts" -o -name "*-test.ts" \) | xargs grep -l "freestyle" 2>/dev/null | head -10Repository: appknox/irene
Length of output: 39
🏁 Script executed:
#!/bin/bash
# Look for any integration or unit tests that might test route lifecycle
rg -n "FreestyleRoute|activate|deactivate" --type-list | head -5Repository: appknox/irene
Length of output: 446
🏁 Script executed:
#!/bin/bash
# Check if there's a README or documentation about the freestyle route
fd -e md -e txt | xargs grep -l -i "freestyle" 2>/dev/null | head -5Repository: appknox/irene
Length of output: 39
Restore the previous Freestyle flags on teardown instead of hard-coding state.
This route mutates a singleton service: activate() sets both showCode and showLabels to true, but deactivate() only touches showCode. This leaves showLabels = true after navigating away from /freestyle, causing later consumers to inherit route-specific state.
Additionally, deactivate() sets showCode = true again, which appears incorrect—it should restore the prior value instead.
Save and restore the previous state for both flags:
Suggested fix
export default class FreestyleRoute extends Route {
`@service`('ember-freestyle') declare emberFreestyle: EmberFreestyleService;
+ private previousShowCode?: boolean;
+ private previousShowLabels?: boolean;
activate() {
+ this.previousShowCode = this.emberFreestyle.showCode;
+ this.previousShowLabels = this.emberFreestyle.showLabels;
this.emberFreestyle.showCode = true;
this.emberFreestyle.showLabels = true;
}
deactivate() {
- this.emberFreestyle.showCode = true;
+ this.emberFreestyle.showCode =
+ this.previousShowCode ?? this.emberFreestyle.showCode;
+ this.emberFreestyle.showLabels =
+ this.previousShowLabels ?? this.emberFreestyle.showLabels;
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/routes/freestyle.ts` around lines 8 - 15, The route currently mutates the
singleton service directly and hard-codes values; update activate() to save the
existing emberFreestyle.showCode and emberFreestyle.showLabels into route
instance properties (e.g. this._prevShowCode, this._prevShowLabels), then set
both flags to true; update deactivate() to restore both flags from those saved
properties (this.emberFreestyle.showCode = this._prevShowCode;
this.emberFreestyle.showLabels = this._prevShowLabels) and clear the saved
properties to avoid leaks. Ensure you reference the existing methods activate
and deactivate and the emberFreestyle service properties showCode and
showLabels.
| &--active { | ||
| background: #e3f2fd; | ||
| color: #1976d2; | ||
| font-weight: 500; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify contrast ratio using a simple calculation
# `#1976d2` (R:25, G:118, B:210) on `#e3f2fd` (R:227, G:242, B:253)
python3 << 'EOF'
def relative_luminance(r, g, b):
def adjust(c):
c = c / 255.0
return c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4
return 0.2126 * adjust(r) + 0.7152 * adjust(g) + 0.0722 * adjust(b)
fg = relative_luminance(25, 118, 210) # `#1976d2`
bg = relative_luminance(227, 242, 253) # `#e3f2fd`
lighter = max(fg, bg)
darker = min(fg, bg)
ratio = (lighter + 0.05) / (darker + 0.05)
print(f"Contrast ratio: {ratio:.2f}:1")
print(f"WCAG AA (4.5:1): {'PASS' if ratio >= 4.5 else 'FAIL'}")
print(f"WCAG AAA (7:1): {'PASS' if ratio >= 7 else 'FAIL'}")
EOFRepository: appknox/irene
Length of output: 122
Improve text contrast for accessibility compliance.
The text color #1976d2 on background #e3f2fd has a contrast ratio of 4.03:1, which falls below the WCAG AA minimum of 4.5:1 for normal text. Use a darker shade of blue to meet accessibility standards.
Suggested fix
&--active {
background: `#e3f2fd`;
- color: `#1976d2`;
+ color: `#1565c0`;
font-weight: 500;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| &--active { | |
| background: #e3f2fd; | |
| color: #1976d2; | |
| font-weight: 500; | |
| } | |
| &--active { | |
| background: `#e3f2fd`; | |
| color: `#1565c0`; | |
| font-weight: 500; | |
| } |
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis
[warning] 95-95: Text does not meet the minimal contrast requirement with its background.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/styles/_freestyle.scss` around lines 93 - 97, The .&--active rule uses
text color `#1976d2` on background `#e3f2fd` which fails WCAG AA; update the color
in the &--active selector to a darker blue that achieves a contrast ratio ≥ 4.5
(for example swap `#1976d2` for a darker shade such as `#0d47a1` or update the
relevant variable), and if your codebase uses a color variable (e.g., a
$primary-... or --color-... token) update that token instead so all references
remain consistent; confirm the final contrast ratio meets WCAG AA for normal
text.
| <div class='freestyle-content'> | ||
| <FreestyleGuide @title='Irene Component Library' @subtitle='Appknox Dashboard Components'> | ||
| {{component (concat (or this.model 'ak-accordion') '/freestyle-section')}} | ||
| </FreestyleGuide> | ||
| </div> |
There was a problem hiding this comment.
This template is wired to the wrong route.
Line 3 reads this.model, but the dynamic selector model in the provided context lives in app/routes/freestyle/component.ts. With this file under freestyle/index.hbs, the selected component_id will not flow here, so the component-specific page will render from the wrong route or not at all. This needs to be app/templates/freestyle/component.hbs, or the route/controller names need to be aligned.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/templates/freestyle/index.hbs` around lines 1 - 5, The template is bound
to the wrong route because it references this.model (used by the component
route) but lives in freestyle/index.hbs; move or rename this template so it
becomes freestyle/component.hbs (so the route will provide the component_id
model), or alternatively update the route/controller wiring to expose the
expected model to the index route; specifically ensure the {{component (concat
(or this.model 'ak-accordion') '/freestyle-section')}} usage inside the
FreestyleGuide receives the route model from the component route (or change the
template to read the correct property exposed by the index route) so component
rendering works as intended.



No description provided.