diff --git a/src/experimental/components/atoms/Icon/Icon.js b/src/experimental/components/atoms/Icon/Icon.js deleted file mode 100644 index bd6347a9..00000000 --- a/src/experimental/components/atoms/Icon/Icon.js +++ /dev/null @@ -1,416 +0,0 @@ -import styles from '!!raw-loader!./Icon.css'; -import varStyles from '!!raw-loader!../../../../shared/variables.css'; -import bootstrapStyles from '!!raw-loader!../../../../shared/themed-bootstrap.css'; - -export default class Icon extends HTMLElement { - constructor() { - // Always call super first in constructor - super(); - // Create a shadow root - const shadow = this.attachShadow({ mode: 'open' }); - - // Add styles - const bootStyles = document.createElement('style'); - bootStyles.textContent = bootstrapStyles; - const variableStyles = document.createElement('style'); - variableStyles.textContent = varStyles; - const itemStyles = document.createElement('style'); - itemStyles.textContent = styles; - shadow.appendChild(bootStyles); - shadow.appendChild(variableStyles); - shadow.appendChild(itemStyles); - } - - connectedCallback() { - if (this.isIconConnected()) { - return; - } - - // Create a container for the icon and circle image - const container = document.createElement('div'); - container.classList.add('icon-container', 'd-inline-block'); - - // Icon attributes - const icon = this.getAttribute('data-icon'); - let size = this.getAttribute('data-size'); - - switch (size) { - case 'small': - size = '16'; - break; - - case 'medium': - size = '24'; - break; - - case 'large': - size = '36'; - break; - - case 'x-large': - size = '54'; - break; - - default: - size = '24'; - break; - } - - const iconElement = document.createElement('span'); - iconElement.innerHTML = this.getIcon(icon, size); - - // Append the icon element to the container - container.appendChild(iconElement); - - // Boolean Attribute adds circle if present - const isHighlighted = this.hasAttribute('is-highlighted'); - - // Add the highlighted class if is-highlighted attribute is present - if (isHighlighted) { - container.classList.add('highlighted'); - } - - // Append the container to the shadow root - this.shadowRoot.appendChild(container); - } - - isIconConnected() { - return this.shadowRoot.querySelector('span') !== null; - } - - getIcon(icon, size) { - switch (icon) { - case 'bicycle': - return ` - - - `; - - case 'bounding-box': - return ` - - - `; - - case 'bounding-box-circle': - return ` - - - `; - - case 'bus-front': - return ` - - - - `; - - case 'bus-front-fill': - return ` - - - `; - - case 'cash': - return ` - - - - `; - - case 'chevron-right': - return ` - - - `; - - case 'chevron-right-circle': - return ` - - - - - - - `; - - case 'chevron-right-circle-fill': - return ` - - - - - - - `; - - case 'chevron-left': - return ` - - - `; - - case 'chevron-left-circle': - return ` - - - - - - - `; - - case 'chevron-left-circle-fill': - return ` - - - - - - - `; - - case 'chevron-up': - return ` - - - `; - - case 'chevron-up-circle': - return ` - - - - - - - `; - - case 'chevron-up-circle-fill': - return ` - - - - - - - `; - - case 'chevron-down': - return ` - - - `; - - case 'chevron-down-circle': - return ` - - - - - - - `; - - case 'chevron-down-circle-fill': - return ` - - - - - - - `; - - case 'house': - return ` - - - `; - case 'house-fill': - return ` - - - - `; - case 'exclamation-circle': - return ` - - - - `; - case 'exclamation-circle-fill': - return ` - - - `; - case 'exclamation-triangle': - return ` - - - - `; - case 'funnel': - return ` - - - `; - case 'funnel-fill': - return ` - - - `; - case 'check-circle': - return ` - - - - `; - case 'check-circle-fill': - return ` - - - `; - case 'calendar': - return ` - - - `; - case 'calendar-fill': - return ` - - - `; - case 'calendar-date': - return ` - - - - `; - - case 'calendar-date-fill': - return ` - - - - `; - - case 'newspaper': - return ` - - - - `; - - case 'building': - return ` - - - - `; - - case 'building-fill': - return ` - - - `; - - case 'buildings': - return ` - - - - `; - - case 'buildings-fill': - return ` - - - `; - - case 'currency-dollar': - return ` - - - `; - - case 'file-earmark': - return ` - - `; - - case 'list-task': - return ` - - - - `; - - case 'journals': - return ` - - - `; - - case 'p-circle': - return ` - - - `; - - case 'p-circle-fill': - return ` - - - `; - - case 'no-parking': - return ` - - - `; - - case 'no-parking-fill': - return ` - - - - `; - - case 'toilet': - return ` - - - `; - - case 'universal-access': - return ` - - - `; - - case 'universal-access-circle': - return ` - - - - `; - - case 'wifi': - return ` - - - - `; - - case 'wifi-off': - return ` - - - `; - - default: - break; - } - } -} diff --git a/src/experimental/index-experimental.js b/src/experimental/index-experimental.js index e570a3c4..19fd4d65 100644 --- a/src/experimental/index-experimental.js +++ b/src/experimental/index-experimental.js @@ -23,7 +23,6 @@ import './components/atoms/FormCheck/cod-formcheck'; import './components/atoms/FormControl/cod-formcontrol'; import './components/atoms/FormLabel/cod-formlabel'; import './components/atoms/FormSelect/cod-formselect'; -import './components/atoms/Icon/cod-icon'; import './components/atoms/Image/cod-image'; import './components/atoms/LegacyButton/cod-legacy-button'; import './components/atoms/LegacyIcon/cod-legacy-icon'; diff --git a/src/experimental/stories/actionbutton.stories.js b/src/experimental/stories/actionbutton.stories.js index da4716e8..11e28152 100644 --- a/src/experimental/stories/actionbutton.stories.js +++ b/src/experimental/stories/actionbutton.stories.js @@ -1,6 +1,6 @@ import { html } from 'lit-html'; import '../components/atoms/ActionButton/cod-action-button'; -import '../components/atoms/Icon/cod-icon'; +import '../../stable/components/Icon/cod-icon'; import { COMMON_STORY_ARGS } from '../../shared/js/storybook/args-utils'; export default { diff --git a/src/experimental/stories/actionbuttonV2.stories.js b/src/experimental/stories/actionbuttonV2.stories.js index d15bf435..ace491ee 100644 --- a/src/experimental/stories/actionbuttonV2.stories.js +++ b/src/experimental/stories/actionbuttonV2.stories.js @@ -1,6 +1,6 @@ import { html } from 'lit-html'; import '../components/atoms/ActionButtonV2/cod-action-button-v2'; -import '../components/atoms/Icon/cod-icon'; +import '../../stable/components/Icon/cod-icon'; import { COMMON_STORY_ARGS } from '../../shared/js/storybook/args-utils'; export default { diff --git a/src/experimental/stories/button.stories.js b/src/experimental/stories/button.stories.js index 067689ed..b36c1b08 100644 --- a/src/experimental/stories/button.stories.js +++ b/src/experimental/stories/button.stories.js @@ -1,5 +1,5 @@ import '../components/atoms/Button/cod-button'; -import '../components/atoms/Icon/cod-icon'; +import '../../stable/components/Icon/cod-icon'; import { COMMON_STORY_ARGS } from '../../shared/js/storybook/args-utils'; export default { diff --git a/src/experimental/stories/icon.stories.js b/src/experimental/stories/icon.stories.js deleted file mode 100644 index 9573c696..00000000 --- a/src/experimental/stories/icon.stories.js +++ /dev/null @@ -1,36 +0,0 @@ -import '../components/atoms/Icon/cod-icon'; -import { COMMON_STORY_ARGS } from '../../shared/js/storybook/args-utils'; - -export default { - tags: ['experimental'], - title: 'Experimental/Icon', - argTypes: { - icon: COMMON_STORY_ARGS.icon, - size: COMMON_STORY_ARGS.longSize, - isHighlighted: { - control: { type: 'boolean' }, - defaultValue: false, - }, - }, -}; -// Template -const Template = (args) => { - const icon = document.createElement('cod-icon'); - icon.setAttribute('data-icon', args.icon); - icon.setAttribute('data-size', args.size); - if (args.isHighlighted) { - icon.setAttribute('is-highlighted', ''); // Set the attribute if isHighlighted is true - } else { - icon.removeAttribute('is-highlighted'); // Remove the attribute if isHighlighted is false - } - return icon; -}; - -export const Icon = { - tags: ['autodocs'], - render: Template.bind({}), - args: { - icon: 'house', - size: 'small', - }, -}; diff --git a/src/experimental/stories/infobutton.stories.js b/src/experimental/stories/infobutton.stories.js index 1cc55980..ba3cce26 100644 --- a/src/experimental/stories/infobutton.stories.js +++ b/src/experimental/stories/infobutton.stories.js @@ -1,5 +1,5 @@ import { html } from 'lit-html'; -import '../components/atoms/Icon/cod-icon'; +import '../../stable/components/Icon/cod-icon'; import '../components/atoms/InfoButton/cod-info-button'; export default { diff --git a/src/experimental/components/atoms/Icon/Icon.css b/src/stable/components/Icon/Icon.css similarity index 62% rename from src/experimental/components/atoms/Icon/Icon.css rename to src/stable/components/Icon/Icon.css index c7cba873..c61c1e12 100644 --- a/src/experimental/components/atoms/Icon/Icon.css +++ b/src/stable/components/Icon/Icon.css @@ -1,4 +1,19 @@ -/* Highlighted styles */ +:host { + --icon-color: inherit; + display: inline-block; +} + +.icon-container { + display: inline-block; + color: inherit; +} +.icon-container svg { + width: 100%; + height: 100%; + fill: currentColor; + stroke: currentColor; +} + .icon-container.highlighted { background-image: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2049%2019%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cellipse%20cx%3D%2224.5%22%20cy%3D%229.5%22%20rx%3D%2224.5%22%20ry%3D%229.5%22%20fill%3D%22%239FD5B3%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat; @@ -6,3 +21,5 @@ background-size: 100% auto; padding-bottom: 0.9%; } + +/*# sourceMappingURL=Icon.css.map */ diff --git a/src/stable/components/Icon/Icon.css.map b/src/stable/components/Icon/Icon.css.map new file mode 100644 index 00000000..9c266efc --- /dev/null +++ b/src/stable/components/Icon/Icon.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["Icon.scss"],"names":[],"mappings":"AAAA;EAEE;EACA;;;AAIF;EACE;EACA;;AAGA;EACE;EACA;EAEA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA","file":"Icon.css"} \ No newline at end of file diff --git a/src/stable/components/Icon/Icon.js b/src/stable/components/Icon/Icon.js new file mode 100644 index 00000000..75a49b44 --- /dev/null +++ b/src/stable/components/Icon/Icon.js @@ -0,0 +1,129 @@ +import styles from '!!raw-loader!./Icon.css'; +import { getIcon } from './icon-helpers.js'; + +const template = document.createElement('template'); +template.innerHTML = ` + +
+ +
+`; + +class Icon extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + // Define reflective properties + static get observedAttributes() { + return ['name', 'library', 'size', 'label', 'is-highlighted']; + } + // Getters and Setters for the attributes + get name() { + return this.getAttribute('name'); + } + + set name(value) { + this.setAttribute('name', value); + } + + get library() { + return this.getAttribute('library'); + } + + set library(value) { + this.setAttribute('library', value); + } + + get size() { + return this.getAttribute('size'); + } + + set size(value) { + this.setAttribute('size', value); + } + + get isHighlighted() { + return this.hasAttribute('is-highlighted'); + } + + connectedCallback() { + if (this.isIconConnected()) { + return; + } + this._renderIcon(); + } + + isIconConnected() { + return this.shadowRoot.querySelector('.icon').innerHTML !== ''; + } + + _renderIcon() { + const container = this.shadowRoot.querySelector('.icon-container'); + const iconElement = this.shadowRoot.querySelector('.icon'); + + // Get attributes (using the getter methods) + const icon = this.name || this.getAttribute('data-icon'); + const label = this.label || icon; + let size = this.size || '24'; // Default to 24 if no size provided + const library = this.library || 'fontawesome'; + + // Check if the font-size is set in the light DOM + const style = window.getComputedStyle(this); + const lightDomSize = style.fontSize; + + if (lightDomSize && lightDomSize !== 'auto') { + size = lightDomSize; // Use the font-size from light DOM if set + } else { + switch (size) { + case 'small': + size = '16'; + break; + case 'medium': + size = '24'; + break; + case 'large': + size = '36'; + break; + case 'x-large': + size = '54'; + break; + default: + size = '24'; + } + } + + // Check if slot has content (SVG provided by the user) + const slotContent = this.querySelector('svg'); + if (slotContent) { + // Return if SVG is provided by the user, as it will render automatically + return; + } + + // Set label for accessibility + if (label) { + container.setAttribute('aria-label', label); + } + + // Set icon using getIcon() with the determined size + iconElement.innerHTML = getIcon(icon, size, library); + + // Handle boolean attribute + if (this.isHighlighted) { + container.classList.add('highlighted'); + } + } + + // Handle attribute changes for reflective properties + attributeChangedCallback(name, oldValue, newValue) { + if (oldValue !== newValue) { + this._renderIcon(); // Re-render the icon if any of the attributes change + } + } +} + +export { Icon as default }; diff --git a/src/stable/components/Icon/Icon.scss b/src/stable/components/Icon/Icon.scss new file mode 100644 index 00000000..70864cfc --- /dev/null +++ b/src/stable/components/Icon/Icon.scss @@ -0,0 +1,26 @@ +:host { + display: inline-block; +} + +// /* Highlighted styles */ +.icon-container { + display: inline-block; + color: inherit; + + // Size will be controlled via the element itself or inherited from parent + svg { + width: 100%; + height: 100%; + // Ensure the SVG also inherits the color + fill: currentColor; + stroke: currentColor; + } +} + +.icon-container.highlighted { + background-image: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2049%2019%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cellipse%20cx%3D%2224.5%22%20cy%3D%229.5%22%20rx%3D%2224.5%22%20ry%3D%229.5%22%20fill%3D%22%239FD5B3%22%2F%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; + background-position-y: bottom; + background-size: 100% auto; + padding-bottom: 0.9%; +} diff --git a/src/experimental/components/atoms/Icon/cod-icon.js b/src/stable/components/Icon/cod-icon.js similarity index 100% rename from src/experimental/components/atoms/Icon/cod-icon.js rename to src/stable/components/Icon/cod-icon.js diff --git a/src/stable/components/Icon/icon-helpers.js b/src/stable/components/Icon/icon-helpers.js new file mode 100644 index 00000000..1c4d24df --- /dev/null +++ b/src/stable/components/Icon/icon-helpers.js @@ -0,0 +1,540 @@ +export function getIcon(icon, size, library = 'fontawesome') { + switch (library.toLowerCase()) { + case 'fontawesome': + switch (icon) { + case 'bicycle': + return ` + + + `; + case 'bounding-box': + return ` + + + `; + + case 'bounding-box-circle': + return ` + + + `; + + case 'bus-front': + return ` + + + + `; + + case 'bus-front-fill': + return ` + + + `; + + case 'cash': + return ` + + + + `; + + case 'chevron-right': + return ` + + + `; + + case 'chevron-right-circle': + return ` + + + + + + + `; + + case 'chevron-right-circle-fill': + return ` + + + + + + + `; + + case 'chevron-left': + return ` + + + `; + + case 'chevron-left-circle': + return ` + + + + + + + `; + + case 'chevron-left-circle-fill': + return ` + + + + + + + `; + + case 'chevron-up': + return ` + + + `; + + case 'chevron-up-circle': + return ` + + + + + + + `; + + case 'chevron-up-circle-fill': + return ` + + + + + + + `; + + case 'chevron-down': + return ` + + + `; + + case 'chevron-down-circle': + return ` + + + + + + + `; + + case 'chevron-down-circle-fill': + return ` + + + + + + + `; + + case 'house': + return ` + + + `; + case 'house-fill': + return ` + + + + `; + case 'exclamation-circle': + return ` + + + + `; + case 'exclamation-circle-fill': + return ` + + + `; + case 'exclamation-triangle': + return ` + + + + `; + case 'funnel': + return ` + + + `; + case 'funnel-fill': + return ` + + + `; + case 'check-circle': + return ` + + + + `; + case 'check-circle-fill': + return ` + + + `; + case 'calendar': + return ` + + + `; + case 'calendar-fill': + return ` + + + `; + case 'calendar-date': + return ` + + + + `; + + case 'calendar-date-fill': + return ` + + + + `; + + case 'newspaper': + return ` + + + + `; + + case 'building': + return ` + + + + `; + + case 'building-fill': + return ` + + + `; + + case 'buildings': + return ` + + + + `; + + case 'buildings-fill': + return ` + + + `; + + case 'currency-dollar': + return ` + + + `; + + case 'file-earmark': + return ` + + `; + + case 'list-task': + return ` + + + + `; + + case 'journals': + return ` + + + `; + + case 'p-circle': + return ` + + + `; + + case 'p-circle-fill': + return ` + + + `; + + case 'no-parking': + return ` + + + `; + + case 'no-parking-fill': + return ` + + + + `; + + case 'toilet': + return ` + + + `; + + case 'universal-access': + return ` + + + `; + + case 'universal-access-circle': + return ` + + + + `; + + case 'wifi': + return ` + + + + `; + + case 'wifi-off': + return ` + + + `; + } + break; + case 'bootstrapicons': + switch (icon) { + // Add Bootstrap icons here + case 'bicycle': + return ` + + `; + + case 'bounding-box': + return ` + +`; + + case 'bounding-box-circles': + return ` + + `; + case 'bus-front': + return ` + + + `; + + case 'bus-front-fill': + return ` + + `; + + case 'cash': + return ` + + + `; + + case 'chevron-right': + return ` + +`; + case 'chevron-left': + return ` + + `; + case 'chevron-up': + return ` + +`; + case 'chevron-down': + return ` + +`; + + case 'house': + return ` + +`; + + case 'house-fill': + return ` + + +`; + + case 'exclamation-circle': + return ` + + +`; + case 'exclamation-circle-fill': + return ` + + +`; + case 'funnel': + return ` + +`; + case 'funnel-fill': + return ` + +`; + + case 'check-circle': + return ` + + +`; + + case 'check-circle-fill': + return ` + +`; + case 'calendar': + return ` + +`; + case 'calendar-fill': + return ` + +`; + + case 'calendar-date': + return ` + + +`; + + case 'calendar-date-fill': + return ` + + + `; + + case 'newspaper': + return ` + + + `; + + case 'building': + return ` + + +`; + + case 'building-fill': + return ` + +`; + + case 'buildings': + return ` + + +`; + case 'currency-dollar': + return ` + +`; + + case 'file-earmark': + return ` + +`; + + case 'list-task': + return ` + + + +`; + + case 'journals': + return ` + + +`; + + case 'p-circle': + return ` + +`; + + case 'p-circle-fill': + return ` + +`; + + case 'no-parking': + return ` + + `; + + case 'no-parking-fill': + return ` + + +`; + + case 'universal-access': + return ` + +`; + + case 'universal-access-circle': + return ` + + +`; + + case 'wifi': + return ` + + +`; + + case 'wifi-off': + return ` + + `; + } + break; + default: + return ` + + `; + } +} diff --git a/src/stable/components/ServiceButton/ServiceButton.css b/src/stable/components/ServiceButton/ServiceButton.css index 9fafa186..0ba80e78 100644 --- a/src/stable/components/ServiceButton/ServiceButton.css +++ b/src/stable/components/ServiceButton/ServiceButton.css @@ -36,7 +36,7 @@ a.service-button:hover::after { right: 0; width: 150px; height: 250%; - z-index: 0; /* Ensures the SVG stays behind the text */ + z-index: 0; background-image: url('data:image/svg+xml,%3Csvg%20width%3D%22155%22%20height%3D%22119%22%20viewBox%3D%220%200%20155%20119%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M154.856%2017L133%2024.7286L133.479%2026L155%2017.3727L154.856%2017Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M116%200.143448L123.731%2022L125%2021.5216L116.377%200L116%200.143448Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M99.0966%2038L121%2030.2881L120.524%2029L99%2037.7372L99.0966%2038Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M100%2015.3607L120.46%2025L121%2023.7789L100.154%2015L100%2015.3607Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M138.639%200L129%2021.4368L130.221%2022L139%200.168816L138.699%200.030508L138.639%200Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M10%2051H8C8%2051%209.96526%2055.0024%209.96526%2055C9.95299%2054.4112%2010%2051%2010%2051Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M14%2056L12.0368%2052C12.047%2052.5913%2012%2056%2012%2056H14Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M108.432%2057.0743L106.62%2059.9007L106.547%2059.8675L90.5589%2052.5769L83.8994%2067.9805L70.5829%2065.6034L63.8384%2068.3442L63.7983%2068.3108L54.6421%2061.3033L54.7744%2061.2366L71.6519%2052.9004L72.6242%2048.3745L72.6783%2048.36L89.2893%2044.2359L89.3246%2044.2572L108.48%2056.9984L108.432%2057.0743ZM72.6997%2079.9656L70.7056%2085.3806H68.8649L70.7411%2080.1177V76.7209L71.6874%2075.8365L72.3245%2078.3134L80.7468%2077.7858C80.7468%2077.7928%2080.749%2077.8025%2080.749%2077.8097L72.6997%2079.9656ZM53.7597%2038.2718L50.9939%2035.5905L54.5312%2036.7361L60.5205%2035.7141L60.5489%2035.7354L62.0403%2036.8123L64.0979%2036.5794L64.9498%2037.226L63.645%2037.9676L66.4839%2038.1934L63.3288%2039.9547L59.7747%2037.321C59.7747%2037.321%2053.7739%2038.2742%2053.7597%2038.2718ZM69.8916%2041.9326L67.4938%2046.9315L67.9045%2042.0965L65.1976%2041.595L68.0743%2040.4254L69.8916%2041.9326ZM9.84537%2067.4812L8.76447%2058.0466L10.9614%2067.833L9.84537%2067.4812ZM134.532%2027.442L124.137%2033.0732L110.719%2055.0587L87.5785%2039.4793L74.1817%2042.3722L73.9387%2028.8635C73.9387%2028.8635%2061.8468%2024.2305%2061.691%2024C61.2239%2024.2471%2050.9843%2029.6312%2050.6185%2030.0805L48.7709%2036.356L53.5165%2041.8636L52.9762%2047.8633L55.8575%2047.9823L57.3702%2049.6794L46.2883%2055.6387L30.7321%2074.08L12.2854%2068.2513C12.2806%2066.2451%2012.2735%2063.0979%2012.2617%2057.6544H8.71959L8.2714%2053.7513H6.28672V63.9084L3.60113%2060.8872L0%2060.6069L5.11387%2070.2459L12.2358%2073.5072C12.2358%2073.5072%2012.2358%2073.5072%2012.2972%2073.5357L34.5481%2083.7308L53.3514%2064.5528L62.4059%2074.3177L60.7848%2083.6643C60.7872%2083.6643%2060.7872%2083.6643%2060.7872%2083.6643L60.5537%2085.0073L66.616%2088L83.6848%2082.5922L84.0645%2081.2111C84.0717%2081.2207%2084.0835%2081.2278%2084.0929%2081.2372L90.3112%2058.4366L113.744%2065.7698L127.627%2037.3092L136.611%2031.8775L140%2028.0005L134.532%2027.442Z%22%20fill%3D%22%23004445%22%2F%3E%3Cpath%20d%3D%22M95.7836%20105.423L89.0367%20104.867L94.0696%20100.799L98.4948%20104.085L102.965%20112.795L95.7836%20105.423ZM53.1592%20117.353L53.1332%20117.365L48.072%20119.246C48.072%20119.246%2050.8662%20114.279%2050.878%20114.248L57.6815%20110.849L53.1592%20117.353ZM32.1744%20113.978L57.4971%20101.262V107.168L44.7789%20112.905L32.1744%20113.978ZM113.544%20107.732C113.449%20107.579%20113.307%20107.402%20113.144%20107.214C113.118%20107.185%20113.097%20107.157%20113.069%20107.125C112.906%20106.944%20112.714%20106.745%20112.497%20106.537C112.449%20106.492%20112.404%20106.449%20112.355%20106.401C112.13%20106.191%20111.887%20105.969%20111.615%20105.734C111.56%20105.686%20111.501%20105.639%20111.445%20105.591C111.187%20105.371%20110.913%20105.144%20110.62%20104.905C110.568%20104.862%20110.518%20104.824%20110.464%20104.781C110.154%20104.53%20109.818%20104.269%20109.473%20104.006C109.357%20103.918%20109.244%20103.829%20109.126%20103.738C108.797%20103.49%20108.457%20103.234%20108.104%20102.974C107.946%20102.856%20107.785%20102.739%20107.625%20102.622C107.327%20102.405%20107.022%20102.185%20106.71%20101.96C106.464%20101.784%20106.211%20101.604%20105.956%20101.423C105.731%20101.262%20105.504%20101.102%20105.272%20100.942C104.897%20100.679%20104.516%20100.414%20104.128%20100.144C103.941%20100.017%20103.755%2099.8881%20103.566%2099.7588C99.4049%2096.9028%2094.5945%2093.7933%2090.3749%2091.1284L83.8079%20105.847L67.5083%20111.059L73.8531%20104.668L63.1398%20108.951L63.1446%20100.861L74.6143%2093.5088L60.3172%2099.4291V94.9167L78.0255%2087.4116L64.4471%2091.3458L64.4447%2088.6354L59.5088%2085C59.3078%2085.1242%2059.0644%2085.2723%2058.7995%2085.4325C58.7759%2085.4493%2058.7475%2085.4636%2058.724%2085.4804C58.5585%2085.5808%2058.3907%2085.6837%2058.2038%2085.7982C58.1069%2085.8582%2058.0052%2085.9202%2057.9035%2085.9824C57.7547%2086.0732%2057.6034%2086.1663%2057.4426%2086.2643C57.3291%2086.3336%2057.2086%2086.4077%2057.0881%2086.4818C56.9392%2086.5752%2056.7902%2086.6659%2056.6319%2086.7639C56.4665%2086.8643%2056.2938%2086.9718%2056.1212%2087.077C55.9747%2087.1679%2055.8329%2087.2564%2055.6792%2087.3495C55.4876%2087.4689%2055.2892%2087.5934%2055.0882%2087.7176C54.9651%2087.7916%2054.847%2087.8657%2054.7217%2087.9421C54.476%2088.0952%2054.2206%2088.2554%2053.963%2088.4154C53.852%2088.4849%2053.7431%2088.5518%2053.632%2088.6211C53.3602%2088.7906%2053.0789%2088.9653%2052.7976%2089.1421C52.6958%2089.2041%2052.5989%2089.2639%2052.4972%2089.3284C52.2041%2089.5102%2051.904%2089.6989%2051.6013%2089.8902C51.4998%2089.9522%2051.4005%2090.0144%2051.2988%2090.0789C50.9845%2090.275%2050.6652%2090.4757%2050.3439%2090.6789C50.2444%2090.7411%2050.1477%2090.8031%2050.0483%2090.8654C49.7079%2091.0803%2049.3652%2091.2957%2049.0199%2091.5155C48.9372%2091.568%2048.8569%2091.6181%2048.7718%2091.6708C48.4125%2091.9003%2048.0484%2092.132%2047.6796%2092.3664C47.6041%2092.4141%2047.5283%2092.462%2047.4504%2092.5121C47.0957%2092.7391%2046.7389%2092.9662%2046.3794%2093.1957C46.2825%2093.2579%2046.188%2093.3199%2046.0909%2093.3797C45.7246%2093.6163%2045.3534%2093.8555%2044.9823%2094.0943C44.902%2094.147%2044.8215%2094.1971%2044.7412%2094.2499C44.3725%2094.4887%2044.0013%2094.7278%2043.6302%2094.9691C43.5403%2095.0266%2043.4528%2095.084%2043.3631%2095.1436C42.992%2095.3826%2042.6232%2095.6264%2042.2519%2095.8679C42.167%2095.9228%2042.0795%2095.9802%2041.9942%2096.0376C41.6469%2096.2646%2041.2992%2096.4917%2040.9541%2096.721C40.8406%2096.7952%2040.7273%2096.8695%2040.6161%2096.9459C40.2734%2097.1705%2039.9377%2097.3952%2039.5996%2097.6198C39.4909%2097.6915%2039.3822%2097.7657%2039.2733%2097.8374C38.9093%2098.0786%2038.55%2098.3224%2038.1931%2098.5616C38.115%2098.614%2038.0371%2098.6667%2037.9614%2098.7192C37.6045%2098.9606%2037.2546%2099.1998%2036.9048%2099.4364C36.8244%2099.4912%2036.7417%2099.5463%2036.6636%2099.6013C36.3255%2099.8332%2035.9946%20100.06%2035.6661%20100.29C35.5786%20100.349%2035.4911%20100.409%2035.406%20100.469C35.1059%20100.677%2034.8127%20100.882%2034.5218%20101.088C34.4107%20101.164%2034.2972%20101.243%2034.1885%20101.32C33.9144%20101.513%2033.6518%20101.702%2033.3871%20101.893C33.2714%20101.975%2033.1507%20102.061%2033.0374%20102.142C32.7749%20102.331%2032.5243%20102.515%2032.2737%20102.696C32.1674%20102.775%2032.0563%20102.856%2031.9522%20102.933C31.7041%20103.115%2031.4701%20103.289%2031.2359%20103.466C31.1368%20103.543%2031.0303%20103.619%2030.9334%20103.693C30.7136%20103.86%2030.508%20104.021%2030.3%20104.183C30.1983%20104.26%2030.092%20104.341%2029.9949%20104.417C29.7987%20104.573%2029.619%20104.716%2029.437%20104.864C29.3401%20104.941%2029.2362%20105.024%2029.1415%20105.099C28.9643%20105.247%2028.8012%20105.383%2028.638%20105.524C28.5552%20105.593%2028.4653%20105.667%2028.3874%20105.737C28.2315%20105.868%2028.0943%20105.995%2027.9548%20106.121C27.8815%20106.188%2027.7988%20106.258%2027.7302%20106.322C27.6073%20106.437%2027.5056%20106.54%2027.3969%20106.647C27.3284%20106.717%2027.2481%20106.788%2027.1865%20106.853C27.0826%20106.963%2026.9997%20107.058%2026.91%20107.159C26.8626%20107.211%2026.8037%20107.274%2026.7611%20107.326C26.6381%20107.472%2026.5387%20107.608%2026.4608%20107.732L25%20111.6L30.4181%20121H109.591L115%20111.6L113.544%20107.732Z%22%20fill%3D%22%23004445%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat; background-position: bottom right; @@ -44,7 +44,7 @@ a.service-button:hover::after { } a.service-button .title { position: relative; - z-index: 1; /* This positions the text above the SVG */ + z-index: 1; font-size: 24px; font-weight: 700; color: #eaf0f0; @@ -52,7 +52,7 @@ a.service-button .title { } a.service-button .subtitle { position: relative; - z-index: 1; /* This positions the text above the SVG */ + z-index: 1; font-size: 16px; font-weight: 400; color: #eaf0f0; diff --git a/src/stable/components/ServiceButton/ServiceButton.css.map b/src/stable/components/ServiceButton/ServiceButton.css.map index be1bc40e..1efb64f5 100644 --- a/src/stable/components/ServiceButton/ServiceButton.css.map +++ b/src/stable/components/ServiceButton/ServiceButton.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["ServiceButton.scss"],"names":[],"mappings":"AA+DA;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA","file":"ServiceButton.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["ServiceButton.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA","file":"ServiceButton.css"} \ No newline at end of file diff --git a/src/stable/docs/Icon.mdx b/src/stable/docs/Icon.mdx new file mode 100644 index 00000000..5f7100a4 --- /dev/null +++ b/src/stable/docs/Icon.mdx @@ -0,0 +1,106 @@ +import { + Meta, + Title, + Subtitle, + Description, + Primary, + Controls, + Stories, + Story, + Source, +} from '@storybook/blocks'; +import * as IconStories from '../stories/icon.stories.js'; + +import '../../../.storybook/docs'; // Import all documentation components + + + +# Icon + +
+ The `Icon` component displays an icon from a specified icon library. +
+ +## Examples + +### Template + + + + + + +## Slots + + + + +## HTML Attributes / JS Properties + +Supported HTML attributes. If the attribute is reflected in a JS property, that attribute will have a 'reflects' tag next to the name. + + + +## Inheriting Size and Color from Parent + +You can control the `Icon` component's `size` and `color` using CSS inheritance from the parent element. This is useful when the `size` attribute is **not** set, allowing the icon to scale with `font-size` and adopt the parent’s `color`. + +### Example + +```html + + +
+ +
+``` + +## Events + + + + +## Methods + + + + +## Custom CSS Properties + + + + +## CSS Parts + + + + +## Dependencies + + + +## Accessibility + +The `Icon` component can be made accessible using the `label` attribute to describe the icon for screen readers. diff --git a/src/stable/index-stable.js b/src/stable/index-stable.js index 50a9c274..1f43a502 100644 --- a/src/stable/index-stable.js +++ b/src/stable/index-stable.js @@ -2,3 +2,4 @@ import './components/GovBanner/cod-gov-banner.js'; import './components/SectionNavigation/cod-section-navigation.js'; import './components/ServiceButton/cod-service-button.js'; import './components/Tag/cod-tag.js'; +import './components/Icon/cod-icon.js'; diff --git a/src/stable/stories/icon.stories.js b/src/stable/stories/icon.stories.js new file mode 100644 index 00000000..a90602e7 --- /dev/null +++ b/src/stable/stories/icon.stories.js @@ -0,0 +1,174 @@ +import '../components/Icon/cod-icon'; +import { COMMON_STORY_ARGS } from '../../shared/js/storybook/args-utils'; + +export default { + title: 'Components/Icon/Inheritance', + argTypes: { + icon: COMMON_STORY_ARGS.icon, + parentSize: { + control: { type: 'select' }, + options: [ + 'default', + 'small', + 'medium', + 'large', + 'x-large', + '16px', + '24px', + '36px', + '48px', + '64px', + ], + defaultValue: 'default', + description: 'Font size set on parent container', + }, + iconSize: { + control: { type: 'select' }, + options: [ + 'inherit', + 'small', + 'medium', + 'large', + 'x-large', + '16', + '24', + '36', + '48', + '64', + ], + defaultValue: 'inherit', + description: 'Size attribute set directly on icon', + }, + parentColor: { + control: { type: 'color' }, + defaultValue: '#000000', + description: 'Color set on parent container', + }, + iconColor: { + control: { type: 'color' }, + defaultValue: 'inherit', + description: 'Color set directly on icon (via CSS variable)', + }, + library: { + control: { type: 'select' }, + options: ['fontawesome', 'bootstrapicons', 'material'], + defaultValue: 'fontawesome', + }, + isHighlighted: { + control: { type: 'boolean' }, + defaultValue: false, + }, + }, +}; + +// Template for inheritance demonstration +const Template = (args) => { + // Create parent container to demonstrate inheritance + const container = document.createElement('div'); + container.style.padding = '20px'; + container.style.border = '1px dashed #ccc'; + container.style.display = 'inline-block'; + + // Apply parent styles based on args + if (args.parentSize !== 'default') { + container.style.fontSize = args.parentSize.endsWith('px') + ? args.parentSize + : `${args.parentSize}px`; + } + container.style.color = args.parentColor; + + // Create info text + const infoText = document.createElement('div'); + infoText.style.marginBottom = '10px'; + infoText.style.fontSize = '14px'; + infoText.innerHTML = `Parent Container: font-size: ${args.parentSize}, color: ${args.parentColor}`; + container.appendChild(infoText); + + // Create the icon + const icon = document.createElement('cod-icon'); + icon.setAttribute('data-icon', args.icon); + if (args.iconSize !== 'inherit') { + icon.setAttribute('data-size', args.iconSize); + } + icon.setAttribute('library', args.library); + + // Apply direct color to icon if not inheriting + if (args.iconColor !== 'inherit') { + icon.style.setProperty('--icon-color', args.iconColor); + } + + if (args.isHighlighted) { + icon.setAttribute('is-highlighted', ''); + } else { + icon.removeAttribute('is-highlighted'); + } + + // Create icon info + const iconInfo = document.createElement('div'); + iconInfo.style.marginTop = '10px'; + iconInfo.style.fontSize = '14px'; + iconInfo.innerHTML = `Icon: size: ${args.iconSize}, color: ${ + args.iconColor === 'inherit' ? 'inherited' : args.iconColor + }`; + + // Append both to container + container.appendChild(icon); + container.appendChild(iconInfo); + + return container; +}; + +export const SizeInheritance = Template.bind({}); +SizeInheritance.args = { + icon: 'house', + parentSize: '48px', + iconSize: 'inherit', + parentColor: '#000000', + iconColor: 'inherit', + library: 'fontawesome', + isHighlighted: false, +}; + +export const ColorInheritance = Template.bind({}); +ColorInheritance.args = { + icon: 'house', + parentSize: 'default', + iconSize: 'large', + parentColor: '#FF5733', + iconColor: 'inherit', + library: 'fontawesome', + isHighlighted: false, +}; + +export const BothInheritance = Template.bind({}); +BothInheritance.args = { + icon: 'house', + parentSize: '64px', + iconSize: 'inherit', + parentColor: '#3366FF', + iconColor: 'inherit', + library: 'fontawesome', + isHighlighted: false, +}; + +export const NoInheritance = Template.bind({}); +NoInheritance.args = { + icon: 'house', + parentSize: '64px', + iconSize: 'small', + parentColor: '#3366FF', + iconColor: '#33CC33', + library: 'fontawesome', + isHighlighted: false, +}; + +export const HighlightedWithInheritance = Template.bind({}); +HighlightedWithInheritance.args = { + icon: 'house', + parentSize: '48px', + iconSize: 'inherit', + parentColor: '#6633CC', + iconColor: 'inherit', + library: 'fontawesome', + isHighlighted: true, +};