@lovett/ui 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/index.d.ts +823 -135
  2. package/dist/index.js +2048 -358
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +44 -2
  5. package/dist/theme-v2.css +228 -0
  6. package/dist/tokens.css +123 -8
  7. package/package.json +1 -1
  8. package/src/__tests__/anchor.test.tsx +422 -0
  9. package/src/__tests__/combobox.test.tsx +677 -0
  10. package/src/__tests__/dropdown-menu.test.tsx +418 -0
  11. package/src/__tests__/helpers/geometry.ts +58 -0
  12. package/src/__tests__/layer-stack.test.tsx +228 -0
  13. package/src/__tests__/modal.test.tsx +180 -6
  14. package/src/__tests__/popover.test.tsx +460 -0
  15. package/src/__tests__/select.test.tsx +543 -0
  16. package/src/__tests__/tooltip.test.tsx +355 -0
  17. package/src/calculator-shell-v2.tsx +19 -39
  18. package/src/code-block.tsx +15 -26
  19. package/src/combobox.tsx +796 -0
  20. package/src/dropdown-menu.tsx +142 -152
  21. package/src/icons/brand.tsx +81 -2
  22. package/src/index.ts +111 -0
  23. package/src/lib/anchor.ts +427 -0
  24. package/src/lib/focus.ts +32 -0
  25. package/src/lib/layer-stack.ts +188 -0
  26. package/src/lib/refs.ts +31 -0
  27. package/src/metric-card.tsx +57 -22
  28. package/src/modal.tsx +149 -9
  29. package/src/page-shell.tsx +91 -2
  30. package/src/popover.tsx +407 -0
  31. package/src/segmented-pill.tsx +33 -10
  32. package/src/select.tsx +646 -0
  33. package/src/stat-row.tsx +108 -70
  34. package/src/styles.css +44 -2
  35. package/src/theme-v2.css +7 -245
  36. package/src/tokens.css +123 -8
  37. package/src/tooltip.tsx +297 -0
  38. package/src/react-syntax-highlighter-prism.d.ts +0 -34
  39. package/src/v2/README.md +0 -208
  40. package/src/v2/__demo__/showcase.tsx +0 -1045
  41. package/src/v2/action.tsx +0 -91
  42. package/src/v2/callout.tsx +0 -76
  43. package/src/v2/document-section.tsx +0 -82
  44. package/src/v2/document-shell.tsx +0 -0
  45. package/src/v2/field-row.tsx +0 -113
  46. package/src/v2/icons.tsx +0 -165
  47. package/src/v2/index.ts +0 -147
  48. package/src/v2/layout.tsx +0 -293
  49. package/src/v2/progress-track.tsx +0 -89
  50. package/src/v2/stat-tile.tsx +0 -129
  51. package/src/v2/states.tsx +0 -271
  52. package/src/v2/status-pill.tsx +0 -74
  53. package/src/v2/theme.css +0 -1861
  54. package/src/v2/timeline.tsx +0 -81
  55. package/src/v2/tokens.ts +0 -228
@@ -8,45 +8,75 @@
8
8
  * BUILD_FRESH per ADR-025 DEVIATION-3: source ships on
9
9
  * `@base-ui/react/menu`, which is NOT in CLAUDE.md §1 allowed deps.
10
10
  * The compound-component surface (Root / Trigger / Content / Item /
11
- * CheckboxItem / Separator / Label / Group) carries over; the
12
- * implementation is a lightweight React Context + Portal + outside-
13
- * click + Escape handler.
11
+ * CheckboxItem / Separator / Label / Group) carries over.
14
12
  *
15
- * Trigger styling per ADR-026 D4 (DQ-4 LIFT): the default trigger
16
- * inherits the secondary Button visual (rounded-xl, `--bg-card` fill,
17
- * 1px `--border`). Consumers can pass `asChild`-equivalent custom
18
- * trigger content; the wrapper applies the button-style classes
19
- * unless `unstyled` is set.
13
+ * Rebuilt on the shared anchored-positioning kit per ADR-0030 Decision G
14
+ * (meta-ads-audit-dashboard task manager; the workspace app's 137 call
15
+ * sites are the other consumer). Same public API, same DOM roles and
16
+ * `data-slot`s; what changed underneath:
17
+ * Positioning is `useAnchoredPosition` (lib/anchor.ts) — the menu now
18
+ * FLIPS to the other side when it cannot fit, instead of being clamped
19
+ * over its own trigger; `side` accepts `left` / `right` too.
20
+ * • Escape goes through the shared dismiss-layer stack (lib/layer-stack.ts)
21
+ * that Modal uses: a menu opened inside a Modal now closes on its own,
22
+ * leaving the Modal open. Before, both closed on one keypress.
23
+ * • Outside-click is `useOutsideClick`, layer-aware — a Select or Popover
24
+ * opened from a menu item is not "outside".
25
+ * • Trigger, Content, Item and CheckboxItem forward refs.
26
+ *
27
+ * Trigger styling per ADR-026 D4 (DQ-4 LIFT): the default trigger inherits
28
+ * the secondary Button visual (rounded-xl, `--bg-card` fill, 1px
29
+ * `--border`). Consumers can pass custom trigger content; the wrapper
30
+ * applies the button-style classes unless `unstyled` is set.
31
+ *
32
+ * Focus stays on the trigger when the menu opens (menus do not steal
33
+ * focus here; items are reached with Tab). Escape closes and refocuses the
34
+ * trigger. Roving arrow-key focus is a follow-up.
35
+ *
36
+ * Token discipline: surface chrome is `POPOVER_SURFACE_STYLE` (shared with
37
+ * Popover — internal `--popover` tokens are allowed inside packages/ui);
38
+ * item hover / focus use public `--surface-overlay`; motion is
39
+ * `.ds-enter-pop`, gated on `positioned` so it never plays from the parked
40
+ * off-screen frame.
20
41
  *
21
42
  * Workspace ADR: ADR-025 (port) + ADR-026 D4 (trigger spec)
22
- * Ported 2026-05-18
43
+ * Ported 2026-05-18 · Rebuilt on lib/anchor 2026-09-05
23
44
  */
24
45
 
25
46
  import {
26
47
  createContext,
48
+ forwardRef,
27
49
  useCallback,
28
50
  useContext,
29
- useEffect,
30
51
  useId,
31
- useLayoutEffect,
32
52
  useMemo,
33
53
  useRef,
34
54
  useState,
35
55
  type ButtonHTMLAttributes,
36
56
  type HTMLAttributes,
37
57
  type ReactNode,
58
+ type RefObject,
38
59
  } from 'react'
39
60
  import { createPortal } from 'react-dom'
40
61
  import { Check } from 'lucide-react'
41
62
  import { cn } from './lib/utils'
63
+ import { composeRefs } from './lib/refs'
64
+ import { useLayer } from './lib/layer-stack'
65
+ import {
66
+ useAnchoredPosition,
67
+ useOutsideClick,
68
+ type AnchorAlign,
69
+ type AnchorSide,
70
+ } from './lib/anchor'
71
+ import { POPOVER_SURFACE_STYLE } from './popover'
42
72
 
43
- type Align = 'start' | 'center' | 'end'
44
- type Side = 'top' | 'bottom'
73
+ type Align = AnchorAlign
74
+ type Side = AnchorSide
45
75
 
46
76
  interface DropdownMenuContextValue {
47
77
  open: boolean
48
78
  setOpen: (next: boolean) => void
49
- triggerRef: React.RefObject<HTMLButtonElement | null>
79
+ triggerRef: RefObject<HTMLButtonElement | null>
50
80
  contentId: string
51
81
  }
52
82
 
@@ -119,23 +149,28 @@ export interface DropdownMenuTriggerProps
119
149
  * secondary Button visual (rounded-xl + `--bg-card` fill + 1px
120
150
  * `--border`). Set `unstyled` to wrap your own button shape.
121
151
  */
122
- export function DropdownMenuTrigger({
123
- unstyled,
124
- className,
125
- onClick,
126
- children,
127
- ...rest
128
- }: DropdownMenuTriggerProps) {
152
+ export const DropdownMenuTrigger = forwardRef<
153
+ HTMLButtonElement,
154
+ DropdownMenuTriggerProps
155
+ >(function DropdownMenuTrigger(
156
+ { unstyled, className, onClick, children, ...rest },
157
+ forwardedRef,
158
+ ) {
129
159
  const { open, setOpen, triggerRef, contentId } =
130
160
  useDropdownMenuCtx('DropdownMenuTrigger')
161
+ const ref = useMemo(
162
+ () => composeRefs<HTMLButtonElement>(forwardedRef, triggerRef),
163
+ [forwardedRef, triggerRef],
164
+ )
131
165
 
132
166
  return (
133
167
  <button
134
- ref={triggerRef}
168
+ ref={ref}
135
169
  type="button"
136
170
  aria-haspopup="menu"
137
171
  aria-expanded={open}
138
172
  aria-controls={open ? contentId : undefined}
173
+ data-state={open ? 'open' : 'closed'}
139
174
  className={cn(
140
175
  !unstyled && 'btn btn-secondary',
141
176
  className,
@@ -149,7 +184,7 @@ export function DropdownMenuTrigger({
149
184
  {children}
150
185
  </button>
151
186
  )
152
- }
187
+ })
153
188
 
154
189
  export interface DropdownMenuContentProps
155
190
  extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
@@ -158,142 +193,98 @@ export interface DropdownMenuContentProps
158
193
  align?: Align
159
194
  /** Pixel offset along the alignment axis. Default 0. */
160
195
  alignOffset?: number
161
- /** Place above (`top`) or below (`bottom`) the trigger. Default `bottom`. */
196
+ /**
197
+ * Preferred side of the trigger. Default `bottom`. Flips to the opposite
198
+ * side when it cannot fit (before the 2026-09-05 rebuild it was clamped
199
+ * over its own trigger instead; only that no-room case differs).
200
+ */
162
201
  side?: Side
163
202
  /** Pixel offset along the side axis. Default 6. */
164
203
  sideOffset?: number
165
204
  }
166
205
 
167
- export function DropdownMenuContent({
168
- children,
169
- align = 'start',
170
- alignOffset = 0,
171
- side = 'bottom',
172
- sideOffset = 6,
173
- className,
174
- style,
175
- ...rest
176
- }: DropdownMenuContentProps) {
206
+ export const DropdownMenuContent = forwardRef<
207
+ HTMLDivElement,
208
+ DropdownMenuContentProps
209
+ >(function DropdownMenuContent(
210
+ {
211
+ children,
212
+ align = 'start',
213
+ alignOffset = 0,
214
+ side = 'bottom',
215
+ sideOffset = 6,
216
+ className,
217
+ style,
218
+ ...rest
219
+ },
220
+ forwardedRef,
221
+ ) {
177
222
  const { open, setOpen, triggerRef, contentId } =
178
223
  useDropdownMenuCtx('DropdownMenuContent')
179
224
  const contentRef = useRef<HTMLDivElement | null>(null)
180
- const [position, setPosition] = useState<{ left: number; top: number } | null>(
181
- null,
182
- )
183
-
184
- // Position relative to the trigger viewport rect. We measure on
185
- // open + on layout changes (scroll / resize) so the panel tracks.
186
- useLayoutEffect(() => {
187
- if (!open) {
188
- setPosition(null)
189
- return
190
- }
191
- const measure = () => {
192
- const triggerEl = triggerRef.current
193
- const contentEl = contentRef.current
194
- if (!triggerEl || !contentEl) return
195
- const triggerRect = triggerEl.getBoundingClientRect()
196
- const contentRect = contentEl.getBoundingClientRect()
197
-
198
- let left = triggerRect.left + alignOffset
199
- if (align === 'end') left = triggerRect.right - contentRect.width - alignOffset
200
- else if (align === 'center')
201
- left =
202
- triggerRect.left +
203
- triggerRect.width / 2 -
204
- contentRect.width / 2 +
205
- alignOffset
206
-
207
- let top =
208
- side === 'bottom'
209
- ? triggerRect.bottom + sideOffset
210
- : triggerRect.top - contentRect.height - sideOffset
211
225
 
212
- // Keep on-screen — clamp to viewport with an 8px gutter.
213
- const gutter = 8
214
- const maxLeft = window.innerWidth - contentRect.width - gutter
215
- const maxTop = window.innerHeight - contentRect.height - gutter
216
- left = Math.max(gutter, Math.min(left, maxLeft))
217
- top = Math.max(gutter, Math.min(top, maxTop))
218
-
219
- setPosition({ left, top })
220
- }
226
+ const {
227
+ ref: positionRef,
228
+ style: positionStyle,
229
+ placement,
230
+ positioned,
231
+ } = useAnchoredPosition<HTMLDivElement>({
232
+ anchorRef: triggerRef,
233
+ side,
234
+ align,
235
+ offset: sideOffset,
236
+ alignOffset,
237
+ enabled: open,
238
+ })
239
+
240
+ // Topmost-wins Escape, shared with Modal and Popover.
241
+ const layer = useLayer({
242
+ enabled: open,
243
+ kind: 'popover',
244
+ elementRef: contentRef,
245
+ onEscape: () => {
246
+ setOpen(false)
247
+ triggerRef.current?.focus()
248
+ },
249
+ })
221
250
 
222
- measure()
223
- window.addEventListener('resize', measure)
224
- window.addEventListener('scroll', measure, true)
225
- return () => {
226
- window.removeEventListener('resize', measure)
227
- window.removeEventListener('scroll', measure, true)
228
- }
229
- }, [open, align, alignOffset, side, sideOffset, triggerRef])
251
+ useOutsideClick([triggerRef, contentRef], () => setOpen(false), {
252
+ enabled: open,
253
+ layer,
254
+ })
230
255
 
231
- // Outside-click + Escape dismissal.
232
- useEffect(() => {
233
- if (!open) return
234
- const onPointerDown = (event: PointerEvent) => {
235
- const target = event.target as Node | null
236
- if (!target) return
237
- if (contentRef.current?.contains(target)) return
238
- if (triggerRef.current?.contains(target)) return
239
- setOpen(false)
240
- }
241
- const onKeyDown = (event: KeyboardEvent) => {
242
- if (event.key === 'Escape') {
243
- event.stopPropagation()
244
- setOpen(false)
245
- triggerRef.current?.focus()
246
- }
247
- }
248
- document.addEventListener('pointerdown', onPointerDown)
249
- document.addEventListener('keydown', onKeyDown)
250
- return () => {
251
- document.removeEventListener('pointerdown', onPointerDown)
252
- document.removeEventListener('keydown', onKeyDown)
253
- }
254
- }, [open, setOpen, triggerRef])
256
+ const ref = useMemo(
257
+ () => composeRefs<HTMLDivElement>(forwardedRef, contentRef, positionRef),
258
+ [forwardedRef, positionRef],
259
+ )
255
260
 
256
261
  if (!open || typeof document === 'undefined') return null
257
262
 
258
- // Two-phase render: first paint measures the content invisibly at
259
- // (0,0) with opacity:0, useLayoutEffect computes the real position,
260
- // and the second paint applies the correct coords + entrance animation.
261
- // The animation classes are gated behind `isPositioned` so the
262
- // entrance never fires from the unpositioned location — that's what
263
- // caused the "flash at top of viewport then jump under the trigger"
264
- // glitch.
265
- const isPositioned = position !== null
266
-
263
+ // Two-phase render (see lib/anchor.ts): the hook parks the first paint
264
+ // off-screen and hidden, measures, then applies real coordinates. The
265
+ // entrance animation is gated on `positioned` so it never fires from the
266
+ // parked location that was the "flash at top of viewport then jump
267
+ // under the trigger" glitch.
267
268
  return createPortal(
268
269
  <div
269
- ref={contentRef}
270
+ ref={ref}
270
271
  id={contentId}
271
272
  role="menu"
272
273
  data-slot="dropdown-menu-content"
273
274
  data-state="open"
274
- data-positioned={isPositioned ? 'true' : 'false'}
275
+ data-side={placement?.side}
276
+ data-align={placement?.align}
277
+ data-positioned={positioned ? 'true' : 'false'}
275
278
  className={cn(
276
279
  'fixed z-[100] min-w-48 max-w-[min(28rem,calc(100vw-16px))]',
277
280
  'p-1.5 overflow-y-auto',
278
281
  'rounded-[var(--radius-lg)]',
279
- isPositioned && 'ds-enter-pop',
282
+ positioned && 'ds-enter-pop',
280
283
  className,
281
284
  )}
282
285
  style={{
283
- // Anchor the unpositioned phase WAY off-screen as a defense
284
- // against any browser/renderer that doesn't fully respect
285
- // visibility:hidden during a same-frame double-render. If the
286
- // first paint slips through, it's at (-99999, -99999), not at
287
- // viewport (0, 0) where a left-edge flash would be visible.
288
- left: position?.left ?? -99999,
289
- top: position?.top ?? -99999,
290
- opacity: isPositioned ? undefined : 0,
291
- pointerEvents: isPositioned ? undefined : 'none',
292
- visibility: isPositioned ? 'visible' : 'hidden',
293
- background: 'rgb(var(--popover))',
294
- color: 'rgb(var(--popover-foreground))',
295
- border: '1px solid rgb(var(--border))',
296
- boxShadow: 'var(--shadow-lg, 0 10px 32px rgba(0,0,0,0.18))',
286
+ ...positionStyle,
287
+ ...POPOVER_SURFACE_STYLE,
297
288
  ...style,
298
289
  }}
299
290
  {...rest}
@@ -302,7 +293,7 @@ export function DropdownMenuContent({
302
293
  </div>,
303
294
  document.body,
304
295
  )
305
- }
296
+ })
306
297
 
307
298
  export interface DropdownMenuItemProps
308
299
  extends ButtonHTMLAttributes<HTMLButtonElement> {
@@ -312,17 +303,17 @@ export interface DropdownMenuItemProps
312
303
  inset?: boolean
313
304
  }
314
305
 
315
- export function DropdownMenuItem({
316
- variant = 'default',
317
- inset,
318
- className,
319
- onClick,
320
- children,
321
- ...rest
322
- }: DropdownMenuItemProps) {
306
+ export const DropdownMenuItem = forwardRef<
307
+ HTMLButtonElement,
308
+ DropdownMenuItemProps
309
+ >(function DropdownMenuItem(
310
+ { variant = 'default', inset, className, onClick, children, ...rest },
311
+ forwardedRef,
312
+ ) {
323
313
  const { setOpen } = useDropdownMenuCtx('DropdownMenuItem')
324
314
  return (
325
315
  <button
316
+ ref={forwardedRef}
326
317
  role="menuitem"
327
318
  type="button"
328
319
  data-slot="dropdown-menu-item"
@@ -348,7 +339,7 @@ export function DropdownMenuItem({
348
339
  {children}
349
340
  </button>
350
341
  )
351
- }
342
+ })
352
343
 
353
344
  export interface DropdownMenuCheckboxItemProps
354
345
  extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
@@ -356,17 +347,16 @@ export interface DropdownMenuCheckboxItemProps
356
347
  onCheckedChange?: (checked: boolean) => void
357
348
  }
358
349
 
359
- export function DropdownMenuCheckboxItem({
360
- checked,
361
- onCheckedChange,
362
- className,
363
- children,
364
- onClick,
365
- disabled,
366
- ...rest
367
- }: DropdownMenuCheckboxItemProps) {
350
+ export const DropdownMenuCheckboxItem = forwardRef<
351
+ HTMLButtonElement,
352
+ DropdownMenuCheckboxItemProps
353
+ >(function DropdownMenuCheckboxItem(
354
+ { checked, onCheckedChange, className, children, onClick, disabled, ...rest },
355
+ forwardedRef,
356
+ ) {
368
357
  return (
369
358
  <button
359
+ ref={forwardedRef}
370
360
  role="menuitemcheckbox"
371
361
  type="button"
372
362
  data-slot="dropdown-menu-checkbox-item"
@@ -399,7 +389,7 @@ export function DropdownMenuCheckboxItem({
399
389
  ) : null}
400
390
  </button>
401
391
  )
402
- }
392
+ })
403
393
 
404
394
  export function DropdownMenuSeparator({
405
395
  className,
@@ -18,11 +18,13 @@
18
18
  * platforms themselves, exactly like the platform-chrome in the ad previews.
19
19
  */
20
20
 
21
+ import type { ReactElement } from 'react'
22
+
21
23
  export interface BrandIconProps {
22
24
  /** Square box size in px; the glyph letterboxes inside (non-square viewBoxes
23
25
  * centre via preserveAspectRatio). Default 16 — a tab/affix glyph. */
24
- size?: number
25
- className?: string
26
+ size?: number | undefined
27
+ className?: string | undefined
26
28
  }
27
29
 
28
30
  /** Meta brand glyph (mono, currentColor). */
@@ -185,3 +187,80 @@ export const BRAND_ICONS = {
185
187
  } as const
186
188
 
187
189
  export type BrandIconKey = keyof typeof BRAND_ICONS
190
+
191
+ // ─── Full-colour marks ───────────────────────────────────────────────────
192
+ //
193
+ // The mono glyphs above are for CONTEXT — inside a red pill, on a tab, next to
194
+ // a label — where a full-colour mark would clash and where `currentColor` is
195
+ // the whole point. These are for the opposite case: a mark standing alone in a
196
+ // list, where colour is what makes a platform recognisable at 16px and there is
197
+ // no surrounding colour to fight.
198
+ //
199
+ // Same source (the owner's logos-apps fork), same nominative use. Three ship
200
+ // monochrome upstream — Instagram, Snapchat, X — so their fills are already
201
+ // `currentColor` here and they follow the theme; baked black would vanish in
202
+ // dark mode, and both are legitimate presentations of those marks.
203
+ //
204
+ // Added 2026-08-30. These began life as a separate `platform-logo.tsx` written
205
+ // without noticing ADR-135 had already solved half the problem. Folded in here
206
+ // rather than left as a rival module: two files of brand marks from one source
207
+ // is how a design system ends up with an Instagram that looks different on two
208
+ // screens.
209
+
210
+ interface ColorMark {
211
+ viewBox: string
212
+ path: ReactElement
213
+ }
214
+
215
+ const COLOR_MARKS: Record<string, ColorMark> = {
216
+ instagram: { viewBox: '0 0 256 256', path: (<><path fill="currentColor" d="M128 23.064c34.177 0 38.225.13 51.722.745c12.48.57 19.258 2.655 23.769 4.408c5.974 2.322 10.238 5.096 14.717 9.575s7.253 8.743 9.575 14.717c1.753 4.511 3.838 11.289 4.408 23.768c.615 13.498.745 17.546.745 51.723s-.13 38.226-.745 51.723c-.57 12.48-2.655 19.257-4.408 23.768c-2.322 5.974-5.096 10.239-9.575 14.718s-8.743 7.253-14.717 9.574c-4.511 1.753-11.289 3.839-23.769 4.408c-13.495.616-17.543.746-51.722.746s-38.228-.13-51.723-.746c-12.48-.57-19.257-2.655-23.768-4.408c-5.974-2.321-10.239-5.095-14.718-9.574c-4.479-4.48-7.253-8.744-9.574-14.718c-1.753-4.51-3.839-11.288-4.408-23.768c-.616-13.497-.746-17.545-.746-51.723s.13-38.225.746-51.722c.57-12.48 2.655-19.258 4.408-23.769c2.321-5.974 5.095-10.238 9.574-14.717c4.48-4.48 8.744-7.253 14.718-9.575c4.51-1.753 11.288-3.838 23.768-4.408c13.497-.615 17.545-.745 51.723-.745M128 0C93.237 0 88.878.147 75.226.77c-13.625.622-22.93 2.786-31.071 5.95c-8.418 3.271-15.556 7.648-22.672 14.764S9.991 35.738 6.72 44.155C3.555 52.297 1.392 61.602.77 75.226C.147 88.878 0 93.237 0 128s.147 39.122.77 52.774c.622 13.625 2.785 22.93 5.95 31.071c3.27 8.417 7.647 15.556 14.763 22.672s14.254 11.492 22.672 14.763c8.142 3.165 17.446 5.328 31.07 5.95c13.653.623 18.012.77 52.775.77s39.122-.147 52.774-.77c13.624-.622 22.929-2.785 31.07-5.95c8.418-3.27 15.556-7.647 22.672-14.763s11.493-14.254 14.764-22.672c3.164-8.142 5.328-17.446 5.95-31.07c.623-13.653.77-18.012.77-52.775s-.147-39.122-.77-52.774c-.622-13.624-2.786-22.929-5.95-31.07c-3.271-8.418-7.648-15.556-14.764-22.672S220.262 9.99 211.845 6.72c-8.142-3.164-17.447-5.328-31.071-5.95C167.122.147 162.763 0 128 0m0 62.27c-36.302 0-65.73 29.43-65.73 65.73s29.428 65.73 65.73 65.73c36.301 0 65.73-29.428 65.73-65.73c0-36.301-29.429-65.73-65.73-65.73m0 108.397c-23.564 0-42.667-19.103-42.667-42.667S104.436 85.333 128 85.333s42.667 19.103 42.667 42.667s-19.103 42.667-42.667 42.667m83.686-110.994c0 8.484-6.876 15.36-15.36 15.36s-15.36-6.876-15.36-15.36s6.877-15.36 15.36-15.36s15.36 6.877 15.36 15.36"/></>) },
217
+ facebook: { viewBox: '0 0 256 256', path: (<><path fill="#1877f2" d="M256 128C256 57.308 198.692 0 128 0S0 57.308 0 128c0 63.888 46.808 116.843 108 126.445V165H75.5v-37H108V99.8c0-32.08 19.11-49.8 48.348-49.8C170.352 50 185 52.5 185 52.5V84h-16.14C152.959 84 148 93.867 148 103.99V128h35.5l-5.675 37H148v89.445c61.192-9.602 108-62.556 108-126.445"/><path fill="#fff" d="m177.825 165l5.675-37H148v-24.01C148 93.866 152.959 84 168.86 84H185V52.5S170.352 50 156.347 50C127.11 50 108 67.72 108 99.8V128H75.5v37H108v89.445A129 129 0 0 0 128 256a129 129 0 0 0 20-1.555V165z"/></>) },
218
+ meta: { viewBox: '0 0 256 171', path: (<><defs><linearGradient id="SVGYeLhubCc" x1="13.878%" x2="89.144%" y1="55.934%" y2="58.694%"><stop offset="0%" stopColor="#0064e1"/><stop offset="40%" stopColor="#0064e1"/><stop offset="83%" stopColor="#0073ee"/><stop offset="100%" stopColor="#0082fb"/></linearGradient><linearGradient id="SVGll66Sdsg" x1="54.315%" x2="54.315%" y1="82.782%" y2="39.307%"><stop offset="0%" stopColor="#0082fb"/><stop offset="100%" stopColor="#0064e0"/></linearGradient></defs><path fill="#0081fb" d="M27.651 112.136c0 9.775 2.146 17.28 4.95 21.82c3.677 5.947 9.16 8.466 14.751 8.466c7.211 0 13.808-1.79 26.52-19.372c10.185-14.092 22.186-33.874 30.26-46.275l13.675-21.01c9.499-14.591 20.493-30.811 33.1-41.806C161.196 4.985 172.298 0 183.47 0c18.758 0 36.625 10.87 50.3 31.257C248.735 53.584 256 81.707 256 110.729c0 17.253-3.4 29.93-9.187 39.946c-5.591 9.686-16.488 19.363-34.818 19.363v-27.616c15.695 0 19.612-14.422 19.612-30.927c0-23.52-5.484-49.623-17.564-68.273c-8.574-13.23-19.684-21.313-31.907-21.313c-13.22 0-23.859 9.97-35.815 27.75c-6.356 9.445-12.882 20.956-20.208 33.944l-8.066 14.289c-16.203 28.728-20.307 35.271-28.408 46.07c-14.2 18.91-26.324 26.076-42.287 26.076c-18.935 0-30.91-8.2-38.325-20.556C2.973 139.413 0 126.202 0 111.148z"/><path fill="url(#SVGYeLhubCc)" d="M21.802 33.206C34.48 13.666 52.774 0 73.757 0C85.91 0 97.99 3.597 110.605 13.897c13.798 11.261 28.505 29.805 46.853 60.368l6.58 10.967c15.881 26.459 24.917 40.07 30.205 46.49c6.802 8.243 11.565 10.7 17.752 10.7c15.695 0 19.612-14.422 19.612-30.927l24.393-.766c0 17.253-3.4 29.93-9.187 39.946c-5.591 9.686-16.488 19.363-34.818 19.363c-11.395 0-21.49-2.475-32.654-13.007c-8.582-8.083-18.615-22.443-26.334-35.352l-22.96-38.352C118.528 64.08 107.96 49.73 101.845 43.23c-6.578-6.988-15.036-15.428-28.532-15.428c-10.923 0-20.2 7.666-27.963 19.39z"/><path fill="url(#SVGll66Sdsg)" d="M73.312 27.802c-10.923 0-20.2 7.666-27.963 19.39c-10.976 16.568-17.698 41.245-17.698 64.944c0 9.775 2.146 17.28 4.95 21.82L9.027 149.482C2.973 139.413 0 126.202 0 111.148C0 83.772 7.514 55.24 21.802 33.206C34.48 13.666 52.774 0 73.757 0z"/></>) },
219
+ x: { viewBox: '0 0 251 256', path: (<><path d="M149.079 108.399L242.33 0h-22.098l-80.97 94.12L74.59 0H0l97.796 142.328L0 256h22.1l85.507-99.395L175.905 256h74.59L149.073 108.399zM118.81 143.58l-9.909-14.172l-78.84-112.773h33.943l63.625 91.011l9.909 14.173l82.705 118.3H186.3l-67.49-96.533z"/></>) },
220
+ linkedin: { viewBox: '0 0 256 256', path: (<><path fill="#0a66c2" d="M218.123 218.127h-37.931v-59.403c0-14.165-.253-32.4-19.728-32.4c-19.756 0-22.779 15.434-22.779 31.369v60.43h-37.93V95.967h36.413v16.694h.51a39.91 39.91 0 0 1 35.928-19.733c38.445 0 45.533 25.288 45.533 58.186zM56.955 79.27c-12.157.002-22.014-9.852-22.016-22.009s9.851-22.014 22.008-22.016c12.157-.003 22.014 9.851 22.016 22.008A22.013 22.013 0 0 1 56.955 79.27m18.966 138.858H37.95V95.967h37.97zM237.033.018H18.89C8.58-.098.125 8.161-.001 18.471v219.053c.122 10.315 8.576 18.582 18.89 18.474h218.144c10.336.128 18.823-8.139 18.966-18.474V18.454c-.147-10.33-8.635-18.588-18.966-18.453"/></>) },
221
+ youtube: { viewBox: '0 0 256 180', path: (<><path fill="red" d="M250.346 28.075A32.18 32.18 0 0 0 227.69 5.418C207.824 0 127.87 0 127.87 0S47.912.164 28.046 5.582A32.18 32.18 0 0 0 5.39 28.24c-6.009 35.298-8.34 89.084.165 122.97a32.18 32.18 0 0 0 22.656 22.657c19.866 5.418 99.822 5.418 99.822 5.418s79.955 0 99.82-5.418a32.18 32.18 0 0 0 22.657-22.657c6.338-35.348 8.291-89.1-.164-123.134"/><path fill="#fff" d="m102.421 128.06l66.328-38.418l-66.328-38.418z"/></>) },
222
+ pinterest: { viewBox: '0 0 256 256', path: (<><path fill="#cb1f27" d="M0 128.002c0 52.414 31.518 97.442 76.619 117.239c-.36-8.938-.064-19.668 2.228-29.393c2.461-10.391 16.47-69.748 16.47-69.748s-4.089-8.173-4.089-20.252c0-18.969 10.994-33.136 24.686-33.136c11.643 0 17.268 8.745 17.268 19.217c0 11.704-7.465 29.211-11.304 45.426c-3.207 13.578 6.808 24.653 20.203 24.653c24.252 0 40.586-31.149 40.586-68.055c0-28.054-18.895-49.052-53.262-49.052c-38.828 0-63.017 28.956-63.017 61.3c0 11.152 3.288 19.016 8.438 25.106c2.368 2.797 2.697 3.922 1.84 7.134c-.614 2.355-2.024 8.025-2.608 10.272c-.852 3.242-3.479 4.401-6.409 3.204c-17.884-7.301-26.213-26.886-26.213-48.902c0-36.361 30.666-79.961 91.482-79.961c48.87 0 81.035 35.364 81.035 73.325c0 50.213-27.916 87.726-69.066 87.726c-13.819 0-26.818-7.47-31.271-15.955c0 0-7.431 29.492-9.005 35.187c-2.714 9.869-8.026 19.733-12.883 27.421a127.9 127.9 0 0 0 36.277 5.249c70.684 0 127.996-57.309 127.996-128.005C256.001 57.309 198.689 0 128.005 0C57.314 0 0 57.309 0 128.002"/></>) },
223
+ tiktok: { viewBox: '0 0 256 290', path: (<><path fill="#ff004f" d="M189.72 104.421c18.678 13.345 41.56 21.197 66.273 21.197v-47.53a67 67 0 0 1-13.918-1.456v37.413c-24.711 0-47.59-7.851-66.272-21.195v96.996c0 48.523-39.356 87.855-87.9 87.855c-18.113 0-34.949-5.473-48.934-14.86c15.962 16.313 38.222 26.432 62.848 26.432c48.548 0 87.905-39.332 87.905-87.857v-96.995zm17.17-47.952c-9.546-10.423-15.814-23.893-17.17-38.785v-6.113h-13.189c3.32 18.927 14.644 35.097 30.358 44.898M69.673 225.607a40 40 0 0 1-8.203-24.33c0-22.192 18.001-40.186 40.21-40.186a40.3 40.3 0 0 1 12.197 1.883v-48.593c-4.61-.631-9.262-.9-13.912-.801v37.822a40.3 40.3 0 0 0-12.203-1.882c-22.208 0-40.208 17.992-40.208 40.187c0 15.694 8.997 29.281 22.119 35.9"/><path d="M175.803 92.849c18.683 13.344 41.56 21.195 66.272 21.195V76.631c-13.794-2.937-26.005-10.141-35.186-20.162c-15.715-9.802-27.038-25.972-30.358-44.898h-34.643v189.843c-.079 22.132-18.049 40.052-40.21 40.052c-13.058 0-24.66-6.221-32.007-15.86c-13.12-6.618-22.118-20.206-22.118-35.898c0-22.193 18-40.187 40.208-40.187c4.255 0 8.356.662 12.203 1.882v-37.822c-47.692.985-86.047 39.933-86.047 87.834c0 23.912 9.551 45.589 25.053 61.428c13.985 9.385 30.82 14.86 48.934 14.86c48.545 0 87.9-39.335 87.9-87.857z"/><path fill="#00f2ea" d="M242.075 76.63V66.516a66.3 66.3 0 0 1-35.186-10.047a66.47 66.47 0 0 0 35.186 20.163M176.53 11.57a68 68 0 0 1-.728-5.457V0h-47.834v189.845c-.076 22.13-18.046 40.05-40.208 40.05a40.06 40.06 0 0 1-18.09-4.287c7.347 9.637 18.949 15.857 32.007 15.857c22.16 0 40.132-17.918 40.21-40.05V11.571zM99.966 113.58v-10.769a89 89 0 0 0-12.061-.818C39.355 101.993 0 141.327 0 189.845c0 30.419 15.467 57.227 38.971 72.996c-15.502-15.838-25.053-37.516-25.053-61.427c0-47.9 38.354-86.848 86.048-87.833"/></>) },
224
+ snapchat: { viewBox: '147.353 39.286 514.631 514.631', path: (<><path style={{ fill: '#FFFC00' }} d="M147.553,423.021v0.023c0.308,11.424,0.403,22.914,2.33,34.268 c2.042,12.012,4.961,23.725,10.53,34.627c7.529,14.756,17.869,27.217,30.921,37.396c9.371,7.309,19.608,13.111,30.94,16.771 c16.524,5.33,33.571,7.373,50.867,7.473c10.791,0.068,21.575,0.338,32.37,0.293c78.395-0.33,156.792,0.566,235.189-0.484 c10.403-0.141,20.636-1.41,30.846-3.277c19.569-3.582,36.864-11.932,51.661-25.133c17.245-15.381,28.88-34.205,34.132-56.924 c3.437-14.85,4.297-29.916,4.444-45.035v-3.016c0-1.17-0.445-256.892-0.486-260.272c-0.115-9.285-0.799-18.5-2.54-27.636 c-2.117-11.133-5.108-21.981-10.439-32.053c-5.629-10.641-12.68-20.209-21.401-28.57c-13.359-12.81-28.775-21.869-46.722-26.661 c-16.21-4.327-32.747-5.285-49.405-5.27c-0.027-0.004-0.09-0.173-0.094-0.255H278.56c-0.005,0.086-0.008,0.172-0.014,0.255 c-9.454,0.173-18.922,0.102-28.328,1.268c-10.304,1.281-20.509,3.21-30.262,6.812c-15.362,5.682-28.709,14.532-40.11,26.347 c-12.917,13.386-22.022,28.867-26.853,46.894c-4.31,16.084-5.248,32.488-5.271,49.008"> </path> <path style={{ fill: '#FFFFFF' }} d="M407.001,473.488c-1.068,0-2.087-0.039-2.862-0.076c-0.615,0.053-1.25,0.076-1.886,0.076 c-22.437,0-37.439-10.607-50.678-19.973c-9.489-6.703-18.438-13.031-28.922-14.775c-5.149-0.854-10.271-1.287-15.22-1.287 c-8.917,0-15.964,1.383-21.109,2.389c-3.166,0.617-5.896,1.148-8.006,1.148c-2.21,0-4.895-0.49-6.014-4.311 c-0.887-3.014-1.523-5.934-2.137-8.746c-1.536-7.027-2.65-11.316-5.281-11.723c-28.141-4.342-44.768-10.738-48.08-18.484 c-0.347-0.814-0.541-1.633-0.584-2.443c-0.129-2.309,1.501-4.334,3.777-4.711c22.348-3.68,42.219-15.492,59.064-35.119 c13.049-15.195,19.457-29.713,20.145-31.316c0.03-0.072,0.065-0.148,0.101-0.217c3.247-6.588,3.893-12.281,1.926-16.916 c-3.626-8.551-15.635-12.361-23.58-14.882c-1.976-0.625-3.845-1.217-5.334-1.808c-7.043-2.782-18.626-8.66-17.083-16.773 c1.124-5.916,8.949-10.036,15.273-10.036c1.756,0,3.312,0.308,4.622,0.923c7.146,3.348,13.575,5.045,19.104,5.045 c6.876,0,10.197-2.618,11-3.362c-0.198-3.668-0.44-7.546-0.674-11.214c0-0.004-0.005-0.048-0.005-0.048 c-1.614-25.675-3.627-57.627,4.546-75.95c24.462-54.847,76.339-59.112,91.651-59.112c0.408,0,6.674-0.062,6.674-0.062 c0.283-0.005,0.59-0.009,0.908-0.009c15.354,0,67.339,4.27,91.816,59.15c8.173,18.335,6.158,50.314,4.539,76.016l-0.076,1.23 c-0.222,3.49-0.427,6.793-0.6,9.995c0.756,0.696,3.795,3.096,9.978,3.339c5.271-0.202,11.328-1.891,17.998-5.014 c2.062-0.968,4.345-1.169,5.895-1.169c2.343,0,4.727,0.456,6.714,1.285l0.106,0.041c5.66,2.009,9.367,6.024,9.447,10.242 c0.071,3.932-2.851,9.809-17.223,15.485c-1.472,0.583-3.35,1.179-5.334,1.808c-7.952,2.524-19.951,6.332-23.577,14.878 c-1.97,4.635-1.322,10.326,1.926,16.912c0.036,0.072,0.067,0.145,0.102,0.221c1,2.344,25.205,57.535,79.209,66.432 c2.275,0.379,3.908,2.406,3.778,4.711c-0.048,0.828-0.248,1.656-0.598,2.465c-3.289,7.703-19.915,14.09-48.064,18.438 c-2.642,0.408-3.755,4.678-5.277,11.668c-0.63,2.887-1.271,5.717-2.146,8.691c-0.819,2.797-2.641,4.164-5.567,4.164h-0.441 c-1.905,0-4.604-0.346-8.008-1.012c-5.95-1.158-12.623-2.236-21.109-2.236c-4.948,0-10.069,0.434-15.224,1.287 c-10.473,1.744-19.421,8.062-28.893,14.758C444.443,462.88,429.436,473.488,407.001,473.488"> </path> <path style={{ fill: '#020202' }} d="M408.336,124.235c14.455,0,64.231,3.883,87.688,56.472c7.724,17.317,5.744,48.686,4.156,73.885 c-0.248,3.999-0.494,7.875-0.694,11.576l-0.084,1.591l1.062,1.185c0.429,0.476,4.444,4.672,13.374,5.017l0.144,0.008l0.15-0.003 c5.904-0.225,12.554-2.059,19.776-5.442c1.064-0.498,2.48-0.741,3.978-0.741c1.707,0,3.521,0.321,5.017,0.951l0.226,0.09 c3.787,1.327,6.464,3.829,6.505,6.093c0.022,1.28-0.935,5.891-14.359,11.194c-1.312,0.518-3.039,1.069-5.041,1.7 c-8.736,2.774-21.934,6.96-26.376,17.427c-2.501,5.896-1.816,12.854,2.034,20.678c1.584,3.697,26.52,59.865,82.631,69.111 c-0.011,0.266-0.079,0.557-0.229,0.9c-0.951,2.24-6.996,9.979-44.612,15.783c-5.886,0.902-7.328,7.5-9,15.17 c-0.604,2.746-1.218,5.518-2.062,8.381c-0.258,0.865-0.306,0.914-1.233,0.914c-0.128,0-0.278,0-0.442,0 c-1.668,0-4.2-0.346-7.135-0.922c-5.345-1.041-12.647-2.318-21.982-2.318c-5.21,0-10.577,0.453-15.962,1.352 c-11.511,1.914-20.872,8.535-30.786,15.543c-13.314,9.408-27.075,19.143-48.071,19.143c-0.917,0-1.812-0.031-2.709-0.076 l-0.236-0.01l-0.237,0.018c-0.515,0.045-1.034,0.068-1.564,0.068c-20.993,0-34.76-9.732-48.068-19.143 c-9.916-7.008-19.282-13.629-30.791-15.543c-5.38-0.896-10.752-1.352-15.959-1.352c-9.333,0-16.644,1.428-21.978,2.471 c-2.935,0.574-5.476,1.066-7.139,1.066c-1.362,0-1.388-0.08-1.676-1.064c-0.844-2.865-1.461-5.703-2.062-8.445 c-1.676-7.678-3.119-14.312-9.002-15.215c-37.613-5.809-43.659-13.561-44.613-15.795c-0.149-0.352-0.216-0.652-0.231-0.918 c56.11-9.238,81.041-65.408,82.63-69.119c3.857-7.818,4.541-14.775,2.032-20.678c-4.442-10.461-17.638-14.653-26.368-17.422 c-2.007-0.635-3.735-1.187-5.048-1.705c-11.336-4.479-14.823-8.991-14.305-11.725c0.601-3.153,6.067-6.359,10.837-6.359 c1.072,0,2.012,0.173,2.707,0.498c7.747,3.631,14.819,5.472,21.022,5.472c9.751,0,14.091-4.537,14.557-5.055l1.057-1.182 l-0.085-1.583c-0.197-3.699-0.44-7.574-0.696-11.565c-1.583-25.205-3.563-56.553,4.158-73.871 c23.37-52.396,72.903-56.435,87.525-56.435c0.36,0,6.717-0.065,6.717-0.065C407.744,124.239,408.033,124.235,408.336,124.235 M408.336,115.197h-0.017c-0.333,0-0.646,0-0.944,0.004c-2.376,0.024-6.282,0.062-6.633,0.066c-8.566,0-25.705,1.21-44.115,9.336 c-10.526,4.643-19.994,10.921-28.14,18.66c-9.712,9.221-17.624,20.59-23.512,33.796c-8.623,19.336-6.576,51.905-4.932,78.078 l0.006,0.041c0.176,2.803,0.361,5.73,0.53,8.582c-1.265,0.581-3.316,1.194-6.339,1.194c-4.864,0-10.648-1.555-17.187-4.619 c-1.924-0.896-4.12-1.349-6.543-1.349c-3.893,0-7.997,1.146-11.557,3.239c-4.479,2.63-7.373,6.347-8.159,10.468 c-0.518,2.726-0.493,8.114,5.492,13.578c3.292,3.008,8.128,5.782,14.37,8.249c1.638,0.645,3.582,1.261,5.641,1.914 c7.145,2.271,17.959,5.702,20.779,12.339c1.429,3.365,0.814,7.793-1.823,13.145c-0.069,0.146-0.138,0.289-0.201,0.439 c-0.659,1.539-6.807,15.465-19.418,30.152c-7.166,8.352-15.059,15.332-23.447,20.752c-10.238,6.617-21.316,10.943-32.923,12.855 c-4.558,0.748-7.813,4.809-7.559,9.424c0.078,1.33,0.39,2.656,0.931,3.939c0.004,0.008,0.009,0.016,0.013,0.023 c1.843,4.311,6.116,7.973,13.063,11.203c8.489,3.943,21.185,7.26,37.732,9.855c0.836,1.59,1.704,5.586,2.305,8.322 c0.629,2.908,1.285,5.898,2.22,9.074c1.009,3.441,3.626,7.553,10.349,7.553c2.548,0,5.478-0.574,8.871-1.232 c4.969-0.975,11.764-2.305,20.245-2.305c4.702,0,9.575,0.414,14.48,1.229c9.455,1.574,17.606,7.332,27.037,14 c13.804,9.758,29.429,20.803,53.302,20.803c0.651,0,1.304-0.021,1.949-0.066c0.789,0.037,1.767,0.066,2.799,0.066 c23.88,0,39.501-11.049,53.29-20.799l0.022-0.02c9.433-6.66,17.575-12.41,27.027-13.984c4.903-0.814,9.775-1.229,14.479-1.229 c8.102,0,14.517,1.033,20.245,2.15c3.738,0.736,6.643,1.09,8.872,1.09l0.218,0.004h0.226c4.917,0,8.53-2.699,9.909-7.422 c0.916-3.109,1.57-6.029,2.215-8.986c0.562-2.564,1.46-6.674,2.296-8.281c16.558-2.6,29.249-5.91,37.739-9.852 c6.931-3.215,11.199-6.873,13.053-11.166c0.556-1.287,0.881-2.621,0.954-3.979c0.261-4.607-2.999-8.676-7.56-9.424 c-51.585-8.502-74.824-61.506-75.785-63.758c-0.062-0.148-0.132-0.295-0.205-0.438c-2.637-5.354-3.246-9.777-1.816-13.148 c2.814-6.631,13.621-10.062,20.771-12.332c2.07-0.652,4.021-1.272,5.646-1.914c7.039-2.78,12.07-5.796,15.389-9.221 c3.964-4.083,4.736-7.995,4.688-10.555c-0.121-6.194-4.856-11.698-12.388-14.393c-2.544-1.052-5.445-1.607-8.399-1.607 c-2.011,0-4.989,0.276-7.808,1.592c-6.035,2.824-11.441,4.368-16.082,4.588c-2.468-0.125-4.199-0.66-5.32-1.171 c0.141-2.416,0.297-4.898,0.458-7.486l0.067-1.108c1.653-26.19,3.707-58.784-4.92-78.134c-5.913-13.253-13.853-24.651-23.604-33.892 c-8.178-7.744-17.678-14.021-28.242-18.661C434.052,116.402,416.914,115.197,408.336,115.197"> </path> <rect x="147.553" y="39.443" style={{ fill: 'none' }} width="514.231" height="514.23"> </rect></>) },
225
+ google: { viewBox: '0 0 256 262', path: (<><path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"/><path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"/><path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"/><path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"/></>) },
226
+ amazon: { viewBox: '0 0 512 512', path: (<><path d="m0 0H512V512H0" fill="#f90"/><path fill="#fff" d="M283 187c-62 2-121 19-121 81 0 43 26 64 61 64 31 0 51-12 68-30 8 11 10 16 24 27q5 3 10-1l31-27q4-4 0-10c-7-11-15-19-15-39v-64c0-27 2-52-18-70-17-16-38-20-62-21-53-1-88 28-93 62q-1 8 7 9l37 5c6 1 9-4 10-8 6-22 29-28 43-23 20 6 18 29 18 45m-36 105c-15 0-25-13-25-30 1-36 29-42 61-42v18c0 32-17 54-36 54m168 106c13-11 26-38 25-57 0-7-1-8-8-10-13-4-46-5-62 10-3 3-2 5 1 5 11-2 45-6 50 2 4 7-8 35-12 47-2 5 2 6 6 3M58 342c96 91 247 94 345 25 7-4 0-12-6-9A376 376 0 0162 337c-4-3-8 2-4 5"/></>) },
227
+ walmart: { viewBox: '-231.5 619.2 64 64', path: (<><path d="M-199.47 640.732c1.488 0 2.778-.794 2.878-1.786l1.488-16.77c0-1.687-1.985-2.977-4.366-2.977-2.48 0-4.366 1.4-4.366 2.977l1.488 16.77c.1.992 1.4 1.786 2.878 1.786M-208.6 646c.794-1.3.695-2.778-.1-3.374L-222.492 633c-1.4-.794-3.572.198-4.763 2.282s-.992 4.465.397 5.26l15.28 7.144c.992.298 2.282-.397 2.977-1.687m18.16 0c.794 1.3 2.084 1.984 2.977 1.588l15.28-7.144c1.4-.794 1.687-3.175.397-5.26-1.2-2.084-3.374-3.076-4.763-2.282l-13.792 9.625c-.794.695-.893 2.183-.1 3.473m-9.027 15.678c1.488 0 2.778.794 2.878 1.786l1.488 16.77c0 1.687-1.985 2.977-4.366 2.977-2.48 0-4.366-1.4-4.366-2.977l1.488-16.77c.1-.992 1.4-1.786 2.878-1.786m9.027-5.277c.794-1.3 2.084-1.985 2.977-1.588l15.28 7.045c1.4.794 1.687 3.175.397 5.26-1.2 2.084-3.374 3.076-4.763 2.282l-13.792-9.625c-.794-.595-.893-2.084-.1-3.374m-18.157 0c.794 1.3.695 2.778-.1 3.374l-13.792 9.625c-1.4.794-3.572-.198-4.763-2.282s-.992-4.465.397-5.26l15.28-7.045c.992-.397 2.282.298 2.977 1.588"/></>) },
228
+ }
229
+
230
+ /** Every platform `<BrandIcon>` can draw in colour. */
231
+ export function hasBrandIcon(name: string): boolean {
232
+ return name in COLOR_MARKS
233
+ }
234
+
235
+ export interface BrandIconRegistryProps extends BrandIconProps {
236
+ /** Platform key, e.g. "facebook", "youtube". */
237
+ name: string
238
+ /** Give a label only when the mark stands alone; decorative beside text. */
239
+ title?: string | undefined
240
+ }
241
+
242
+ /**
243
+ * A full-colour platform mark, looked up by key. Use when the platform is
244
+ * chosen at runtime; use the named mono `Brand*` components when it is known
245
+ * at author time and the mark sits in coloured chrome.
246
+ */
247
+ export function BrandIcon({ name, size = 16, className, title }: BrandIconRegistryProps) {
248
+ const mark = COLOR_MARKS[name]
249
+ if (!mark) return null
250
+ return (
251
+ <svg
252
+ viewBox={mark.viewBox}
253
+ width={size}
254
+ height={size}
255
+ className={className}
256
+ // Meta is 256x171 and YouTube 256x180 — assuming square would stretch them.
257
+ preserveAspectRatio="xMidYMid meet"
258
+ role={title ? 'img' : undefined}
259
+ aria-hidden={title ? undefined : true}
260
+ focusable="false"
261
+ >
262
+ {title && <title>{title}</title>}
263
+ {mark.path}
264
+ </svg>
265
+ )
266
+ }