feat(catalog): add initial idp.global component catalog with primitives, composed views, and full-page showcases
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
import {
|
||||
DeesElement,
|
||||
html,
|
||||
property,
|
||||
customElement,
|
||||
css,
|
||||
type TemplateResult,
|
||||
} from '@design.estate/dees-element';
|
||||
import * as lucideIcons from 'lucide';
|
||||
import {
|
||||
Activity,
|
||||
ArrowUp,
|
||||
Bell,
|
||||
Bolt,
|
||||
Box,
|
||||
Building2,
|
||||
Check,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Clock,
|
||||
Cloud,
|
||||
Copy,
|
||||
CreditCard,
|
||||
Fingerprint,
|
||||
Globe,
|
||||
Grid2x2,
|
||||
Home,
|
||||
Key,
|
||||
Laptop,
|
||||
Lock,
|
||||
LogOut,
|
||||
Mail,
|
||||
MapPin,
|
||||
Monitor,
|
||||
MonitorSmartphone,
|
||||
Nfc,
|
||||
Phone,
|
||||
Plus,
|
||||
Power,
|
||||
QrCode,
|
||||
Search,
|
||||
Settings,
|
||||
Shield,
|
||||
SmartphoneNfc,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TriangleAlert,
|
||||
User,
|
||||
Users,
|
||||
Wallet,
|
||||
X,
|
||||
createElement,
|
||||
type IconNode,
|
||||
} from 'lucide';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
|
||||
export type TIdpIconName =
|
||||
| 'activity'
|
||||
| 'alert'
|
||||
| 'alert-triangle'
|
||||
| 'arrow-up'
|
||||
| 'bell'
|
||||
| 'bolt'
|
||||
| 'box'
|
||||
| 'building'
|
||||
| 'building2'
|
||||
| 'building-2'
|
||||
| 'check'
|
||||
| 'chevron'
|
||||
| 'chevron-down'
|
||||
| 'chevron-right'
|
||||
| 'clock'
|
||||
| 'cloud'
|
||||
| 'copy'
|
||||
| 'credit'
|
||||
| 'device'
|
||||
| 'edit'
|
||||
| 'fingerprint'
|
||||
| 'gear'
|
||||
| 'globe'
|
||||
| 'grid'
|
||||
| 'home'
|
||||
| 'key'
|
||||
| 'laptop'
|
||||
| 'location'
|
||||
| 'lock'
|
||||
| 'logout'
|
||||
| 'mail'
|
||||
| 'monitor'
|
||||
| 'monitor-smartphone'
|
||||
| 'nfc'
|
||||
| 'phone'
|
||||
| 'plus'
|
||||
| 'power'
|
||||
| 'qr'
|
||||
| 'search'
|
||||
| 'settings'
|
||||
| 'shield'
|
||||
| 'smartphone-nfc'
|
||||
| 'trash'
|
||||
| 'user'
|
||||
| 'users'
|
||||
| 'wallet'
|
||||
| 'waveform'
|
||||
| 'x'
|
||||
| `lucide:${string}`;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-icon': IdpIcon;
|
||||
}
|
||||
}
|
||||
|
||||
const iconNodes: Record<string, IconNode> = {
|
||||
activity: Activity,
|
||||
alert: TriangleAlert,
|
||||
'alert-triangle': TriangleAlert,
|
||||
'arrow-up': ArrowUp,
|
||||
bell: Bell,
|
||||
bolt: Bolt,
|
||||
box: Box,
|
||||
building: Building2,
|
||||
building2: Building2,
|
||||
'building-2': Building2,
|
||||
check: Check,
|
||||
chevron: ChevronRight,
|
||||
'chevron-down': ChevronDown,
|
||||
'chevron-right': ChevronRight,
|
||||
clock: Clock,
|
||||
cloud: Cloud,
|
||||
copy: Copy,
|
||||
credit: CreditCard,
|
||||
device: MonitorSmartphone,
|
||||
edit: SquarePen,
|
||||
fingerprint: Fingerprint,
|
||||
gear: Settings,
|
||||
globe: Globe,
|
||||
grid: Grid2x2,
|
||||
home: Home,
|
||||
key: Key,
|
||||
laptop: Laptop,
|
||||
location: MapPin,
|
||||
lock: Lock,
|
||||
logout: LogOut,
|
||||
mail: Mail,
|
||||
monitor: Monitor,
|
||||
'monitor-smartphone': MonitorSmartphone,
|
||||
nfc: Nfc,
|
||||
phone: Phone,
|
||||
plus: Plus,
|
||||
power: Power,
|
||||
qr: QrCode,
|
||||
search: Search,
|
||||
settings: Settings,
|
||||
shield: Shield,
|
||||
'smartphone-nfc': SmartphoneNfc,
|
||||
trash: Trash2,
|
||||
user: User,
|
||||
users: Users,
|
||||
wallet: Wallet,
|
||||
waveform: Activity,
|
||||
x: X,
|
||||
};
|
||||
|
||||
const toKebab = (valueArg: string): string => valueArg
|
||||
.replace(/^lucide:/, '')
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
||||
.toLowerCase();
|
||||
|
||||
const toLucideExportName = (valueArg: string): string => valueArg
|
||||
.replace(/^lucide:/i, '')
|
||||
.split(/[-_: ]+/)
|
||||
.filter(Boolean)
|
||||
.map((partArg) => `${partArg.charAt(0).toUpperCase()}${partArg.slice(1)}`)
|
||||
.join('');
|
||||
|
||||
@customElement('idp-icon')
|
||||
export class IdpIcon extends DeesElement {
|
||||
public static demo = () => html`<idp-icon name="shield"></idp-icon>`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String })
|
||||
public accessor name: TIdpIconName = 'shield';
|
||||
|
||||
@property({ type: Number })
|
||||
public accessor size = 18;
|
||||
|
||||
private lastRenderKey = '';
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: currentColor;
|
||||
line-height: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#iconContainer {
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
}
|
||||
#iconContainer svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.75;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
private resolveIconNode(): IconNode {
|
||||
const rawName = String(this.name || 'shield');
|
||||
const iconName = toKebab(rawName);
|
||||
const aliasNode = iconNodes[iconName];
|
||||
if (aliasNode) {
|
||||
return aliasNode;
|
||||
}
|
||||
|
||||
const exportName = toLucideExportName(rawName);
|
||||
const lucideNode = (lucideIcons as Record<string, unknown>)[exportName];
|
||||
if (Array.isArray(lucideNode)) {
|
||||
return lucideNode as IconNode;
|
||||
}
|
||||
|
||||
return Shield;
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div id="iconContainer" style="--icon-size: ${this.size}px"></div>
|
||||
`;
|
||||
}
|
||||
|
||||
public updated(): void {
|
||||
const renderKey = `${this.name}:${this.size}`;
|
||||
if (this.lastRenderKey === renderKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastRenderKey = renderKey;
|
||||
|
||||
const container = this.shadowRoot?.querySelector('#iconContainer');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '';
|
||||
const iconElement = createElement(this.resolveIconNode(), {
|
||||
color: 'currentColor',
|
||||
size: this.size,
|
||||
strokeWidth: 1.75,
|
||||
});
|
||||
iconElement.setAttribute('aria-hidden', 'true');
|
||||
container.appendChild(iconElement);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user