diff --git a/package-lock.json b/package-lock.json index aa3c866b4f3..145060f5e6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -268,37 +268,6 @@ "node": ">=16" } }, - "node_modules/@awesome.me/webawesome": { - "version": "3.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@ctrl/tinycolor": "4.1.0", - "@floating-ui/dom": "^1.6.13", - "@lit/react": "^1.0.8", - "@shoelace-style/animations": "^1.2.0", - "@shoelace-style/localize": "^3.2.2", - "composed-offset-position": "^0.0.6", - "lit": "^3.2.1", - "marked": "^11.2.0", - "nanoid": "^5.1.5", - "qr-creator": "^1.0.0" - }, - "engines": { - "node": ">=14.17.0" - } - }, - "node_modules/@awesome.me/webawesome/node_modules/marked": { - "version": "11.2.0", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "license": "MIT", @@ -16510,23 +16479,6 @@ "version": "2.26.2", "license": "MIT" }, - "node_modules/nanoid": { - "version": "5.1.6", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, "node_modules/nanospinner": { "version": "1.2.2", "dev": true, @@ -23979,7 +23931,6 @@ "devDependencies": { "@adobe/leonardo-contrast-colors": "^1.1.0", "@arethetypeswrong/cli": "^0.18.2", - "@awesome.me/webawesome": "^3.6.0", "@custom-elements-manifest/analyzer": "^0.11.0", "@lion/ui": "^0.16.1", "@shoelace-style/shoelace": "^2.20.1", @@ -24016,7 +23967,6 @@ "vitest": "^4.1.5" }, "peerDependencies": { - "@awesome.me/webawesome": "^3.0.0", "@lion/ui": "0.x", "lit": "3.x" } diff --git a/packages/craftcms-cp/.storybook/preview.ts b/packages/craftcms-cp/.storybook/preview.ts index 82cdb1d6cf0..253dd644efa 100644 --- a/packages/craftcms-cp/.storybook/preview.ts +++ b/packages/craftcms-cp/.storybook/preview.ts @@ -4,12 +4,15 @@ import type { } from '@storybook/web-components-vite'; import '../src/styles/cp.css'; import './preview.css'; -import {icons} from '@lion/ui/icon.js'; -import {html} from 'lit'; import {withThemeByDataAttribute} from '@storybook/addon-themes'; import {setCustomElementsManifest} from '@storybook/web-components'; import manifest from '../dist/custom-elements.json' with {type: 'json'}; import {setStorybookHelpersConfig} from '@wc-toolkit/storybook-helpers'; +import { + createUrlIconResolver, + getIconUrl, + setIconResolver, +} from '../src/utilities/icons.js'; setStorybookHelpersConfig({ /** hides the `arg ref` label on each control */ @@ -24,9 +27,18 @@ setStorybookHelpersConfig({ setCustomElementsManifest(manifest); -icons.addIconResolver('craft', (iconSet: string, name: string) => { - return html`
${iconSet} - ${name}
`; -}); +const FONT_AWESOME_CDN_URL = + 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.0.0/svgs'; + +setIconResolver( + createUrlIconResolver((name, family, variant) => { + if (family === 'custom-icons' || variant === 'custom-icons') { + return null; + } + + return getIconUrl(name, family, variant, FONT_AWESOME_CDN_URL); + }) +); const preview: Preview = { parameters: { diff --git a/packages/craftcms-cp/package.json b/packages/craftcms-cp/package.json index bcf5abfccad..9158dd3a9a7 100644 --- a/packages/craftcms-cp/package.json +++ b/packages/craftcms-cp/package.json @@ -70,14 +70,12 @@ }, "homepage": "https://github.com/craftcms/npm-packages#readme", "peerDependencies": { - "@awesome.me/webawesome": "^3.0.0", "@lion/ui": "0.x", "lit": "3.x" }, "devDependencies": { "@adobe/leonardo-contrast-colors": "^1.1.0", "@arethetypeswrong/cli": "^0.18.2", - "@awesome.me/webawesome": "^3.6.0", "@custom-elements-manifest/analyzer": "^0.11.0", "@lion/ui": "^0.16.1", "@shoelace-style/shoelace": "^2.20.1", diff --git a/packages/craftcms-cp/scripts/build.js b/packages/craftcms-cp/scripts/build.js index 02188d5466c..5abe1915977 100755 --- a/packages/craftcms-cp/scripts/build.js +++ b/packages/craftcms-cp/scripts/build.js @@ -47,7 +47,7 @@ async function generateBundle(config = {}) { ...(await resolveFrom('./src/services/**/!(*.(styles|test)).ts')), }, minify: !isDeveloping, - external: ['lit', '@lion/ui', '@awesome.me/webawesome'], + external: ['lit', '@lion/ui'], format: ['esm'], sourcemap: true, dts: true, diff --git a/packages/craftcms-cp/scripts/generate-vue-wrappers.js b/packages/craftcms-cp/scripts/generate-vue-wrappers.js index 7dfe170ef6d..d37387adccc 100644 --- a/packages/craftcms-cp/scripts/generate-vue-wrappers.js +++ b/packages/craftcms-cp/scripts/generate-vue-wrappers.js @@ -544,16 +544,6 @@ const ALL_COMPONENTS = [ className: 'CraftDisclosure', importPath: '../components/disclosure/disclosure', }, - { - tagName: 'craft-drawer', - className: 'CraftDrawer', - importPath: '../components/drawer/drawer', - }, - { - tagName: 'craft-dropdown', - className: 'CraftDropdown', - importPath: '../components/dropdown/dropdown', - }, { tagName: 'craft-indicator', className: 'CraftIndicator', @@ -620,7 +610,7 @@ const ALL_COMPONENTS = [ importPath: '../components/input-file/selected-file-list', }, { - tagName: 'c-tooltip', + tagName: 'craft-tooltip', className: 'CraftTooltip', importPath: '../components/tooltip/tooltip', }, diff --git a/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.test.ts b/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.test.ts new file mode 100644 index 00000000000..32a934c6331 --- /dev/null +++ b/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.test.ts @@ -0,0 +1,58 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import type CraftBreadcrumbItem from './breadcrumb-item.js'; +import './breadcrumb-item.js'; + +async function createItem( + attrs: Record = {}, + text = 'Entries' +): Promise { + const element = document.createElement( + 'craft-breadcrumb-item' + ) as CraftBreadcrumbItem; + for (const [name, value] of Object.entries(attrs)) { + element.setAttribute(name, value); + } + element.textContent = text; + document.body.append(element); + await element.updateComplete; + return element; +} + +beforeEach(() => { + document.body.innerHTML = ''; +}); + +describe('craft-breadcrumb-item', () => { + it('renders a span label without href', async () => { + const element = await createItem(); + expect(element.shadowRoot!.querySelector('a')).toBeNull(); + expect(element.shadowRoot!.querySelector('span.label')).not.toBeNull(); + }); + + it('renders a link when href is set', async () => { + const element = await createItem({href: '/entries'}); + const link = element.shadowRoot!.querySelector('a.label'); + expect(link).not.toBeNull(); + expect(link!.getAttribute('href')).toBe('/entries'); + }); + + it('exposes href as a property', async () => { + const element = await createItem({href: '/entries'}); + expect(element.href).toBe('/entries'); + }); + + it('has a separator slot for breadcrumbs to fill', async () => { + const element = await createItem(); + const separator = document.createElement('span'); + separator.slot = 'separator'; + separator.textContent = '/'; + element.append(separator); + await element.updateComplete; + + const slot = element.shadowRoot!.querySelector( + 'slot[name="separator"]' + ); + expect(slot).not.toBeNull(); + expect(slot!.assignedElements()).toEqual([separator]); + }); +}); diff --git a/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.ts b/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.ts index f7f4a1c3ea0..da10c484f65 100644 --- a/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.ts +++ b/packages/craftcms-cp/src/components/breadcrumb-item/breadcrumb-item.ts @@ -1,34 +1,73 @@ -import {css} from 'lit'; -import WaBreadcrumbItem from '@awesome.me/webawesome/dist/components/breadcrumb-item/breadcrumb-item.js'; - -export default class CraftBreadcrumbItem extends WaBreadcrumbItem { - static override get styles() { - return [ - WaBreadcrumbItem.styles, - css` - :host { - --wa-font-weight-action: 400; - --wa-space-s: var(--c-spacing-sm); - white-space: nowrap; - display: inline-flex; - align-items: center; - color: inherit; - } - - .start { - margin-inline-end: var(--c-spacing-sm); - } - - .end { - margin-inline-start: var(--c-spacing-sm); - } - - .separator { - color: var(--c-text-quiet); - margin: 0 var(--c-spacing-md); - } - `, - ]; +import {css, html, LitElement, nothing} from 'lit'; +import {property} from 'lit/decorators.js'; + +/** + * A single crumb inside `craft-breadcrumbs`. Renders its default-slot content + * as a link when `href` is set. `craft-breadcrumbs` appends separator content + * into the `separator` slot. + */ +export default class CraftBreadcrumbItem extends LitElement { + /** When set, the label is rendered as a link. */ + @property({reflect: true}) href?: string; + + /** The link target (only used when `href` is set). */ + @property() target?: '_blank' | '_parent' | '_self' | '_top'; + + /** The link rel (only used when `href` and `target` are set). */ + @property() rel = 'noreferrer noopener'; + + static override styles = css` + :host { + white-space: nowrap; + display: inline-flex; + align-items: center; + color: inherit; + } + + .label { + display: inline-flex; + align-items: center; + font-weight: 400; + color: inherit; + text-decoration: none; + } + + a.label:hover { + text-decoration: underline; + } + + slot[name='start']::slotted(*) { + margin-inline-end: var(--c-spacing-sm); + } + + slot[name='end']::slotted(*) { + margin-inline-start: var(--c-spacing-sm); + } + + slot[name='separator']::slotted(*) { + color: var(--c-text-quiet); + margin: 0 var(--c-spacing-md); + } + `; + + override render() { + const label = this.href + ? html`` + : html``; + + return html` + + ${label} + + + `; } } diff --git a/packages/craftcms-cp/src/components/copy-button/copy-button.ts b/packages/craftcms-cp/src/components/copy-button/copy-button.ts index 29438d147a2..6d56028f4ed 100644 --- a/packages/craftcms-cp/src/components/copy-button/copy-button.ts +++ b/packages/craftcms-cp/src/components/copy-button/copy-button.ts @@ -149,7 +149,7 @@ export default class CraftCopyButton extends LitElement { override render() { return html` - ${this.tooltipLabel} + ${this.tooltipLabel}