From f6d838558e3ad363475932a10197d28e3eb90f1b Mon Sep 17 00:00:00 2001 From: Erik Tallang Date: Wed, 4 Dec 2024 08:46:44 +0100 Subject: [PATCH] feat(icon): initial icon implementation --- bun.lockb | Bin 122648 -> 123120 bytes package.json | 9 ++-- src/components/icon/icon.ts | 73 +++++++++++++++++++++++++++++++ src/components/icon/index.ts | 2 + src/components/icon/package.json | 12 +++++ src/components/icon/react.ts | 10 +++++ src/components/icon/store.ts | 40 +++++++++++++++++ 7 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 src/components/icon/icon.ts create mode 100644 src/components/icon/index.ts create mode 100644 src/components/icon/package.json create mode 100644 src/components/icon/react.ts create mode 100644 src/components/icon/store.ts diff --git a/bun.lockb b/bun.lockb index d6563dd03fb68c2df1d96bc2947ba7604f316b8d..c1b55d0567624b7696bb0409a37236ae470af406 100755 GIT binary patch delta 20526 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

MoFZQq)S20P7;gdY# z4YwGt@G!GT9_wjgGkCG5MgG7bN$3{`<5N6L#)ehk>il7FykTAyUJ-0IUVV<`x>Oj$w^>MU>evvk{MLYc?KlL=&ogRJ`FK^qyuzLLiUxG8^Uw@)D2> zf&2hS-5_28QXItN>YEKmgLp}Ov$0`_Bn{+~>c<<4!KEtPMR0u;u4xlJb}G0OMfV}N z!Mx0;ol8?}M~Z4WxD18+9o%4rOKm1eBNXl^xGaSW36-QF3im=KcLSW7BB8lnfo0%S zyI(7Hy<13SRvoRr3TZP$=yg1GxheoN(jp8!$5J=Qs15fM|;{pLIYh1js zc3W~waB?a*v)Un1CRsqD&Z@$vgqY+{AkpN6)Wjs$h?XQ&6m^DV>vJS+Jh9yco7oH2#J?#K}n;f_7pbsP8Rt^=+rSI&w3M*vS-UxP@uY6 zls7ZU?ICqXO4PcU$v6X&h5XM@vjeZ_Y-S^PY!{1hKk|;`?YqRwx4=;aP(`x|L-zo& zMHsgf#c4O7rxd4Wj6djVF(!9X7PIJh;}US{bhrU7iI;V4=K^;~Qj$#q*BhLoQr$nk zi)Js+21nI}>xG%vdpy=^F}h%VQ*%oJ*H_786F4P1*$ur-?kOuS&>oUHWQko&tcaKP zu<&08Cm25N#^aLA#v(L6jz4S~&vx?CB#V5XWF*Eu+$6@;s^(OcGj#qCNR$&!AIRx2 zFYRfO<9eX#if&4%NuC1MRlogRG(Uf8e!rM=fx=&c8Zs#SmY}3Q;I>pm0A|y;y$WHHN~m-Kq9xV zsvL{H>%-&vndRPn)$@>A$&HYxiLOe5uOLxXT*)QmfPQLnR1?xbO~P!0Bp{KyDl3)z z6(p)A1`xv;YE$!+Im0{{p-D)G6YhFQ*eE^Y<*VRmejrVfiP?B;szomAuj}HAyMPi!Vf`Gmj_y8??H-I;u8CrlOk3*dSw-20VW&@g2+L2N!aE5)({ymV;1y{@Eu{lhJU^7T++pk4rdh?3qLAiWPj zAEE}pPooV%YXZ$RISkYYU~g6^`dUeE0;La8$`7-~t{7nHR}}DF0t{BKhG|5Qf*&3t&z{3d)! zRvnp|vzP+DGOMY*HkfrJ;X~8|c#{Nt{tqbm^S@RQP1A!)swXIS8)4bgXG9}|y#}H? zU?|BiJA%@vcA`L|#CAqNS#{HB4^Xo23F->kPt&JrbPyRgAWCrSlQ)nuZ?PSa$f)gaH--@^HD99(G`j_C7_|5}6>1Ha zY6e89V4=xGDZ^JlNwr+l6D4+qCO=LMd}U#MJ4LM4tX|cuh*IurHJK>&&n8eRWh*E} zZPVnPB;fNnCA-%(yFFSwQPRJm$)M_r@|c41Q4Gki6oyohgIa>eDX9)2AiE=4JW*ng zYVy-4EtDs;_!CT9(VPl3gOi%Ua+W&h>L@EB7M!x{1 zPbF3QUsI6F-qH;IyOc8jS2jue|H3Z$uWXX`|Ak#r?ead<75F?(|GG(H{GYa4(kMK> zJ5oj@(^&q)U6PFP`DgYj#sB{)!+$ozf6|T`SO_ToPt5<|F8Qx)ZupLY&%e1X|2aKR z%5VCgO;Xt`X_Wu7N&aV({QrED?5b^wv}^ubo8+El<6bcEwuh}eyV#8no@-??-#pjG z8d(LaqopT=E27x z^yH@zdhx(THddb(BW%DgAoS*;i*3w@PeJI*KSAinBe;$E^H~TR^6Ll#cOisR+aPZiFqlyv)YJc?QB(ycA(;?*596MerPiZFo7tNbbGd#-jKbgl+k0gwZ^3 zg^ihbF~S&r0bwi;U1`JB;1q=M{1b%jc*H6jYtLsPH1q2SEj)I$jV16!2ow2DgdKR| zt2XuwU-l|mFdr>=)yg{YZfk7(O-Q4rS?SJrnvHek?l0I_H=cvAJ1<9Q<=)e6tOp;1 zFo~Z=*pmmoXrmi)gvtB@!rnY|hK)VTryxw>pCIhRBWBuIUp@1z`dI1YseMm}JA1<}8Hc_;rNidF*5xo4^+#Eao>6mheQo zjZNgs5I)bpM>vUhbJ*Bqz6K#~&=ER#?RmM7Q6=ko@!;&c9(ZRJEE`yT z+{H8Be)jS0oaO6|CQC;?^GdqRw!Bp@-O+wTTYtwSK6rhD9%XlCTQ)vwGVYwqpiQ|M zcT0AaP3zs?$A036N!HYMZf^xfj$a$Fxt&Miaht zSlMelbqBh8C%PNbdM@uocS9Pr)5uBHWR$OQozmE3pLHi)>=AnDgK1lQSSlJ%_38a~O(Z0P_wvW%+i}vk9 z`ylP-vHQ?INGtbQSt-8>>E$=jzBjDwAYb+d+P5F=gH*=5?MM3{ZQpNYNB9Fso8CnG z-n8QOd-I!UUn$yGYGucHYAM=x0PTZxg3AZcK1ibuSlQdW6jJsUduXrEH8Y{`38kMd@8I_+0a{0%tJo#=-L$x5D zcGpKK>fQ}kbf&b{jmv8xRts1#;eYRLk%vG{7S_o6kMnl ztp7%=0{6SswK~;NqS)3w#vgkrEYJPP)ky!FMXj<>tN5XxJeYOQg`WZ#*30kj4|Maz zWn^_+e1w43p^Ww?M6u5eigBZgLu}HX%N0FiNm)>(dIOWXVf)31PfRSK(;tu24=pbB zlvyoF-)hSZ$@CSTzFFPTbY7Yb>0Q*Ur1~NwhSjrsYfgYpej?IP*dKhkChlpsh|D&PFKXu4oc z*EI$VJ|DLeO=4NNk?xy}qHipVbfeoOI?CJtz7&gMS$%K1PdE*n0p0=50@R5y;zTS9 z7WZOVJ3HN9F9lu#1n@FIcYySDzaHQL&;`{fAP>j~MgwDk0-z8m0>%RqfMTEoms|n}IFBR$v>j9oPZv1a<+tf!BdOz+PY<@CL9S;J^~V8}Ow6HlWKNx)`GG=X8@q zw@-AV_kv*USbcW~*eO61KsS`BBBCAZl1krY`v84`{s1Pc)Dj2>S^=#Ay0upO0Pu{fEX{*wAF6$wQNcCdX=qRtPXJ1IvIo7`6jC z0^NYU(Cq_u0Ly__#M1UGpiMtS(OuzofbI_Io{;7c%^8w)y=!|2`0VOPbEZlA8{i|L zY6=j40eA(1fJ_E`hVqFM;Xjhx8*r`UR&l88I>K%FHCCJ3uql z3-AFvG?|PW0KQM?C`0l@vLzcm4e9*>ssI&86(CBptSQh0pxM`00jf)569zm3&_E{w z2>>~OS$JDm7kekLX#oBoP`TY22s!{r1;~YM0F5EJG`TkU9Qj^vAQ|Wd^aPTC9)K0- z4v0XpgGhf&w&{U(1=V0@_Wyzye@CFb|+^BL83j**%G+&*JApmG>%eYcA8-J86DS1^ z0*8RNfs?>7pd2^~903jkCxGMBPj7+I6H`l11Jo+L1!urhOR|8o0ClTA#mMeG;9cN6 za88qnQf1GHn;lrw%GvxrRFvccjZ$&?C=nm>n4auD1Kt5>L_Y=eqVzPnOtzl`a7x97 z@}fS`>;@<0mk=sM^%fHI*@{}Kpcn2A6T5D0XHj-0#^cp3mYe)t1<;^s5# zZ8z#ZSBTYs*F{-J7AceS(t15dJb;)(iCaT#34{SPf#yInAQYeutqz+SKrj#lkk5t! z=>T;;#;S7NBl{LeM?FA1eOf^d7b`olfLd+9UZc$opLOHJ$xf_^xYvpK_|nv`g;}|F zMee3C$D8bMWf9@A;Ze{I5thy@l8qPhIx}y!Sdsg93K9_8VgUF^!z zV#1@sqiI@*I$c9(>TM~-(|{D_!_h*^HZ6uy6s{X1uj{=#HYs{!+x z>}wy3m^N)to7R#aYAz#<;mE9UO+R}(%$X)cEb79%l3L?PqCFpJ=8{vVi(D}QHqqg& zkyxUBKwmm`1T1d)PLX4Ufu%(t2DObv3>IF8{(Ei2pdI4VF03J&EGBkEi@B)Rl|}kq zf~5y6|Ja&w-?dXZ`QFDfw+;gML>jUpFm{q#3) z`O9ATW?jRh*PUq(8^x==Sr5b8Msb%)(Vyd0Te0YD@U*YjYL>`Lf0%cBXZtlC`}#I> zmhxp)F+T-0zEf2keipQ%su)ewud0~+ELx!H{q&c5H9q-iY5zBBjB)0$$yL8ehaL zrYWL7XS;Ic$jYs4%3@s@nh_D+7So`%_@gg6Pk(Xux0eckSY!G5pwmKst5^QjqD}Sc zclpH`lT};v=!drGkLp@?cxA}`s0~T%dcYQNmwq*}-kDK7M&|e0+x|>_P z$(EdT#vB*#_QMqVNF*jPk3gle`fI*p(%mjiZWJJ2)*KHQb=G<80 zv}h`N;kq_je{sm;ZwHT@_sUGCf&Mn})X$E9=hyY+&X{3!1TH`uwACL8K5IVT!q4A* zqtilvUg%c8Dou1+ofiT9v7S72n4)O4 zIxgIjn78j!YoHh?-Q;aRRR<;gy&+Ky=hqPnVG;e*zEmvqx05-g?KVYK9rd+RO(h1s zdwDV#IWux z)^I;atm=;0uRqy5=;2j&@PcJiU076jnCS%G1&NmAiKnUcK;#)1rT{ zXkhD6U7GBKEeeXxiTs;r{<>;Oem%**SnO@HsvpZPiQCj`2>6`@*SL_dVzvZ;h zU!(q-wrq0LiZhR#F`kVD?gSh7>F-xfO}EFi`R#mXr$tI*agTD>U%d9Ya%9bnpQiXY zE%Z0BmTJ9+kDYls(;2g)u`u^QTKyI6RO{;JzTI5ChtooTXIuM=3lU+zzw^5@hJ}c^ zJTfJX7h&2`~Y;1Upq`y#o@YM%CH9mc2q=9Lt z9pw=E_%X*B6CN(isg)-H_PiLAii1E*D=`;ZLsBcTa0Fss6GxzqR^P}2zwY zU$8TqQ#dWvg{%C2*w)^BCFHm>1`B_!0mw=_YKVjZtgc+xN`3#Qo;z}$JU7*0Ct!es zPvwI-{Y3Te#iWVL1JF9{IHOldJN<}`16f^GAZ!C!e!ag=hQs2Mfh_Qe3ER{i0`R-y8#@6CgHL z=^NpnhW$(Jbdj9KqL`*yE?6dFHi*(RoTXLC_YO`YZWx1O_MX@CuO3W8-6N3`rgMb| z90GIAPJf|oPBR?(;5*l=&Vxg|$S1q*V%88g0%!B@hhR(5?}!tsKT0lX^8Pu+ye&2D zim;@^%k-DYbyiL1XQo_qgFzdUa){O6Fnj$G)al61_va(V6dutAjjIwP=BHyH&|g8j zym8TYkTkjpERZ!FKte=0GBsC~b`WtH`{&mI54S-t1QL&{Bk z9W6O>YaT4x+4cMxB{!x1f2v~T4BjB@RB>(WUmwPNwBcjQVAiV^p?sTChgA1UzmtjT zJpK9(AO36V-aw@k>>q6;bvic>z66VwaFQw=)O}`RgZPS^8GVL(Fg->q@>({l8{8dM z{!g*4!}OT7;#=~>tzs0ukcfs^sHe*N{&mEfKcm)8HDIU2L8S4!2CW~;80-?bdc$ik z4RS6;zds}HW#QDMzu-0unjSpj+eb^B7Wy0Sb9uw==f4&Bi!-L9Xg?g?uD=Q|sz^DK zMLH#!7<^_8S8OcH~ih$t|EIR8?HC)zPLFOGtO1`KgagzyCCxtcb-E_Lq)Y*7FqAF z-#6Ndq+Ax?R)0JnS$NRnf>+ZAa9n)92#>{OVRzM0o4>MS;kuICiJD7e;p`*Ia*=he z_y}2JHr5!$A`Q2@i-b||8TA#u(Y*f{kvC3 z3@u4mAdF&g9&1s(XOeOc>$uZHEY4$XeD&A#M}0!79vqT>4GAK{BdFwc;wqJ;KhK|D zXHahL3rxLHh=@Rz`pbXsx^;8=1lRsRONv^Y5-s!L==z@mNS>T~==0rsw!whbU>Hmn z8Tn{cO|dkeB^jsRuJbQwN&CpmZiKdT+oW+t;^JoiRJa zqj9LY{>K+$x}Uk*X1Ncp2rwTb=svDIUCs2X2a(Tx8C(TlQuN!%kJ3fY@$i{Du%H{e z+CPey0?g-Lby~QHDdRCFequR@Z&Zd_iLz~7Eq=C`)lR!4aSjHJvtd9xX5R$~Q+IU# zBG_qgZydv!4s9tGH7BqR_OVse)uH;d6E}usryQ6JnJzzh<3}$Vx}8~HFjO&@HYfNV zs+dwY?8*2ihvUh3{MD$8u?1Pu*$(CdzjYaSGz~L|`tj84*MC2r+&geX9uzcBZWK<< zsgv35vk8#vL0IWu39NPE_qZOe3GE9pZO^g^wf@lm>yby)l^tRY%W};@%ug?*WTh4bgQra~JuuvCx;!#$gzC z?jm*$ZjRFDGh>~~jOg!A4K2tNC+4s~v2Zr4X3Q8nDmqH^UJTPgvysuQh0IOtnvHz3 zSA#Rp!QR?#0XFvXsh9@ot641){l$l?SqpJ~0jnyK=CEpF=X~a|zx`@90N1puu!;K4 zW_4<4rL{yEZ_H)Ks*1UD(IH|zd&tDi%`ASu>tyzM4RLZY>nKdin6DV}7P4Btk=3q( zI}fpABkSfu-<8D_fv#D21l3F4%xdkA+{C6badiWbdh08yam*Dm4#LudA9rYfEybb5&D0XKyvABA LPHVmRM*9B)$4Of? diff --git a/package.json b/package.json index 34563b9..580a153 100644 --- a/package.json +++ b/package.json @@ -13,23 +13,24 @@ }, "dependencies": { "@lit/react": "^1.0.6", - "@storybook/addon-themes": "^8.4.6", "lit": "^3.2.1" }, "devDependencies": { "@biomejs/biome": "1.9.4", "@chromatic-com/storybook": "^3.2.2", "@computas/designsystem-breadcrumbs": "workspace:*", + "@computas/designsystem-icon": "workspace:*", "@storybook/addon-essentials": "^8.4.6", + "@storybook/addon-themes": "^8.4.6", "@storybook/blocks": "^8.4.6", "@storybook/manager-api": "^8.4.6", "@storybook/test": "^8.4.6", "@storybook/theming": "^8.4.6", "@storybook/web-components": "^8.4.6", "@storybook/web-components-vite": "^8.4.6", - "@types/node": "^22.9.0", + "@types/node": "^22.10.1", "storybook": "^8.4.6", - "typescript": "~5.7.0", - "vite": "^6.0.0" + "typescript": "~5.7.2", + "vite": "^6.0.2" } } diff --git a/src/components/icon/icon.ts b/src/components/icon/icon.ts new file mode 100644 index 0000000..1be0f85 --- /dev/null +++ b/src/components/icon/icon.ts @@ -0,0 +1,73 @@ +import DOMPurify from 'dompurify'; +import { LitElement, css, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; + +import { getIcon } from './store'; + +type IconSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; + +@customElement('cx-icon') +export class Icon extends LitElement { + static readonly styles = css` + :host { + --_icon-size: 32px; + + display: inline-block; + width: var(--_icon-size); + height: var(--_icon-size); + line-height: 0; + } + + :host([size='xxs']) { + --_icon-size: 8px; + } + + :host([size='xs']) { + --_icon-size: 16px; + } + + :host([size='sm']) { + --_icon-size: 24px; + } + + :host([size='md']) { + --_icon-size: 32px; + } + + :host([size='lg']) { + --_icon-size: 40px; + } + + :host([size='xl']) { + --_icon-size: 48px; + } + + :host([size='xxl']) { + --_icon-size: 56px; + } + + svg { + width: 100%; + height: 100%; + } + `; + + @property({ type: String, reflect: true }) + name = ''; + + // Setting this to reflect: true will make the size attribute reflect to the DOM, which makes the current + // CSS-selector-based approach for sizing work in React. If another approach is used, this whole property may be removed. + @property({ type: String, reflect: true }) + size: IconSize | undefined = undefined; + + render() { + return html`${unsafeHTML(DOMPurify.sanitize(getIcon(this.name)?.svg ?? ''))}`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'cx-icon': Icon; + } +} diff --git a/src/components/icon/index.ts b/src/components/icon/index.ts new file mode 100644 index 0000000..6f38ea5 --- /dev/null +++ b/src/components/icon/index.ts @@ -0,0 +1,2 @@ +export * from './icon'; +export { addIcons } from './store'; diff --git a/src/components/icon/package.json b/src/components/icon/package.json new file mode 100644 index 0000000..f4d65af --- /dev/null +++ b/src/components/icon/package.json @@ -0,0 +1,12 @@ +{ + "name": "@computas/designsystem-icon", + "version": "1.0.0", + "type": "module", + "private": "true", + "scripts": { + "build": "tsup" + }, + "devDependencies": { + "tsup": "^8.3.5" + } +} diff --git a/src/components/icon/react.ts b/src/components/icon/react.ts new file mode 100644 index 0000000..cc0f36c --- /dev/null +++ b/src/components/icon/react.ts @@ -0,0 +1,10 @@ +import { createComponent } from '@lit/react'; +import * as React from 'react'; + +import { Icon } from './index'; + +export const CxIcon = createComponent({ + tagName: 'cx-icon', + elementClass: Icon, + react: React, +}); diff --git a/src/components/icon/store.ts b/src/components/icon/store.ts new file mode 100644 index 0000000..a46f983 --- /dev/null +++ b/src/components/icon/store.ts @@ -0,0 +1,40 @@ +interface IconData { + svg: string; +} +type IconRegistry = Record; + +let _cxGlobalIconsStore: IconRegistry = {}; + +/** + * Add icons to the global icon store to make them available for use in the `/Icon` component. + * + * You can add multiple icons at once. The key of the input object is the icon name corresponding to the `name` + * prop in the `/Icon` component. While this can be any string, it is recommended to use the icon name as the key. + * Some selectors depend on the `filledColor` icons to keep `filledColor` in the icon name to work properly. + * @param icons - An object of icon names and their corresponding SVG data. + * + * @example + * ```ts + * import { addIcons } from '@computas/designsystem/icon'; + * + * // import the icon data (SVG string) + * import download from '@computas/designsystem/icon/svg/download?raw'; + * + * addIcons({ + * download: { svg: download } + * }); + * ``` + */ +export const addIcons = (icons: IconRegistry) => { + _cxGlobalIconsStore = { ..._cxGlobalIconsStore, ...icons }; +}; + +export const getIcon = (name: string): IconData | undefined => { + // Need to check `name` because it can be `undefined` on initial render depending on property vs attribute + if (name && !_cxGlobalIconsStore[name]) { + throw new Error( + `Icon "${name}" not found. Ensure the icon name is correct and that it has been added to the global icon store using \`addIcons\`.`, + ); + } + return _cxGlobalIconsStore[name]; +};