Skip to content

fix: let apps register their own icons (BITS-206) - #23

Merged
PhilReinking merged 3 commits into
mainfrom
fix/bits-206-app-registered-icons
Oct 11, 2026
Merged

PhilReinking merged 3 commits into
mainfrom
fix/bits-206-app-registered-icons

Conversation

@PhilReinking

@PhilReinking PhilReinking commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

D9Icon now looks icons up in the Font Awesome library when it renders, so icons an app adds with library.add work. @deck9/ui registers only the 5 icons its components render.

Part of BITS-206 (Input still registers its icons, change below).

Heads-up (release note): apps now register their own icons. Every icon an app names in D9Icon or an icon prop must be added with library.add in the app's entry point.

  • D9Icon props stay as they are. The icons export now lists only D9's 5 names, brands is empty.
  • .storybook/preview.ts registers the 4 demo icons the stories use, like an app does.
  • The Icons Overview page now shows those 5 icons instead of the full list.
  • Removed the unused numeric-input icon and its .d.ts.
  • tests/Icon.spec.ts uses GitLab, not GitHub: GitHub was in D9's old list, so the spec passed without this fix. Comment fixed.

Tested: D9Button-only app on the packed build: 68.04 → 46.51 kB gzip, 110 → 5 icons. Storybook: D9's icons, demo icons, app-registered icons render. npm test passes, the brand spec fails on main.
Not tested: Input running. Both Input entries build with the change, and every listed name renders.

D9's own icons

check (Select), chevron-down (Select), circle-notch (Button loading, Spinner), ellipsis (Menu, as ellipsis-h), eye-dropper (Input color picker, as eyedropper).

Input change, after the release

Checked in a scratch copy of Input: vue-tsc shows the same 19 errors as without the change, both builds pass, npm ls shows one fontawesome-svg-core. Public form bundle: 222.20 → 205.56 kB gzip, 110 → 30 icons.

  1. Add @fortawesome/fontawesome-svg-core, @fortawesome/free-solid-svg-icons and @fortawesome/free-brands-svg-icons (^6.5.1) to dependencies, and bump @deck9/ui.
  2. resources/js/forms/classic.ts (public form), after the ClassicForm import:
import { library } from "@fortawesome/fontawesome-svg-core";
import {
    faArrowUp19, faBolt, faCalendar, faChevronLeft, faChevronRight,
    faCircleNotch, faCrown, faEnvelope, faFileLines, faFilePdf,
    faFileVideo, faFileWaveform, faHeart, faLink, faPhone, faPoo,
    faStar, faTree, faTrophy, faTurnDown, faXmark,
} from "@fortawesome/free-solid-svg-icons";
import {
    faFacebook, faGithub, faInstagram, faLinkedin, faTwitter,
} from "@fortawesome/free-brands-svg-icons";

// @deck9/ui registers only the icons its own components render
library.add(
    faArrowUp19, faBolt, faCalendar, faChevronLeft, faChevronRight,
    faCircleNotch, faCrown, faEnvelope, faFileLines, faFilePdf,
    faFileVideo, faFileWaveform, faHeart, faLink, faPhone, faPoo,
    faStar, faTree, faTrophy, faTurnDown, faXmark,
    faFacebook, faGithub, faInstagram, faLinkedin, faTwitter,
);
  1. resources/js/app.ts (editor and dashboard), after the lodash/debounce import:
import { library } from "@fortawesome/fontawesome-svg-core";
import {
    faArrowUp19, faArrowUpRightFromSquare, faAsterisk, faBold, faBolt,
    faCalendar, faChartPie, faChevronDown, faChevronLeft, faChevronRight,
    faChevronUp, faCircleCheck, faCircleDot, faCircleInfo, faCirclePlay,
    faCirclePlus, faClipboard, faCloudArrowDown, faCloudArrowUp, faCode,
    faCodeBranch, faCrown, faEnvelope, faEye, faEyeSlash, faGear, faGlobe,
    faGripVertical, faHeading, faHeart, faImage, faItalic, faLayerGroup,
    faLink, faListOl, faListUl, faLocationArrow, faLock, faMessage,
    faPencil, faPhone, faPlus, faPoo, faPuzzlePiece, faQuestion,
    faQuoteRight, faShield, faSignal, faSquareCheck, faStar, faTextSlash,
    faTrash, faTree, faTrophy, faUnderline, faUser, faUserShield, faXmark,
} from "@fortawesome/free-solid-svg-icons";

// @deck9/ui registers only the icons its own components render
library.add(
    faArrowUp19, faArrowUpRightFromSquare, faAsterisk, faBold, faBolt,
    faCalendar, faChartPie, faChevronDown, faChevronLeft, faChevronRight,
    faChevronUp, faCircleCheck, faCircleDot, faCircleInfo, faCirclePlay,
    faCirclePlus, faClipboard, faCloudArrowDown, faCloudArrowUp, faCode,
    faCodeBranch, faCrown, faEnvelope, faEye, faEyeSlash, faGear, faGlobe,
    faGripVertical, faHeading, faHeart, faImage, faItalic, faLayerGroup,
    faLink, faListOl, faListUl, faLocationArrow, faLock, faMessage,
    faPencil, faPhone, faPlus, faPoo, faPuzzlePiece, faQuestion,
    faQuoteRight, faShield, faSignal, faSquareCheck, faStar, faTextSlash,
    faTrash, faTree, faTrophy, faUnderline, faUser, faUserShield, faXmark,
);
  1. icon="…" to name="…" on D9Icon in Navigator.vue:17 and :35, FormButton.vue:18 and :31, CallToActionButton.vue:15 (all in forms/classic/layout/). D9Icon has no icon prop. These render today only because D9Icon checks its default name user and the stray attribute then wins. Without faUser in the form they show nothing.

Names Input writes that are aliases: sort-numeric-up → faArrowUp19, times and close → faXmark, add → faPlus, check-circle → faCircleCheck, check-square → faSquareCheck, cloud-download → faCloudArrowDown, cloud-upload → faCloudArrowUp, cog → faGear, external-link → faArrowUpRightFromSquare, pencil-alt → faPencil, play-circle → faCirclePlay, plus-circle → faCirclePlus, remove-format → faTextSlash.

The rating icon comes from saved form data (options.icon, fallback star). The editor offers only star, heart, poo, bolt, tree, crown and trophy, so those are registered. Any other saved name no longer renders.

🤖 Generated with Claude Code

PhilReinking and others added 3 commits October 11, 2026 17:03
…rary (BITS-206)

D9Icon now looks the name up in the Font Awesome library when it renders,
so icons an app adds with library.add work. The library only gets the five
icons D9 components render themselves. Storybook registers its demo icons
in its preview, like an app. The unused numeric-input icon is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ookup (BITS-206)

GitHub was in D9's old icon list, so the spec passed without the fix.
GitLab never was: the spec now fails on main and passes with this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@PhilReinking PhilReinking left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK at dfae967, CI green. One small point inline, fine as a follow-up.

Checked against main in WebKit and Chromium: aliases (times, cog, ellipsis-h) resolve, and a name in both sets picks fab. An icon added after a D9Icon mounted shows only on its next mount. A bare <D9Icon /> renders nothing and warns once. All icon names Input writes are covered by the two lists in the PR text. The gitlab spec fails with main's src/Icon.

Comment thread src/Icon/registerIcons.ts
// Custom
numericInput.definition
);
export default definitions.map(({ iconName }): string => iconName);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The Button, Select and Input stories use icons as their icon control options (Button.stories.ts:17, Select.stories.ts:13, Input.stories.ts:19). That list now holds only these 5, not the demo icons the stories default to. Add the demo names, or drop the options as in Icon.stories.ts.

@PhilReinking
PhilReinking merged commit f941883 into main Oct 11, 2026
1 check passed
@PhilReinking
PhilReinking deleted the fix/bits-206-app-registered-icons branch October 11, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant