@sovereignfs/ui 0.33.0 → 0.37.0

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 (45) hide show
  1. package/README.md +1 -1
  2. package/dist/CheckableListRow.module.css +95 -0
  3. package/dist/Dialog.module.css +12 -12
  4. package/dist/IconPicker.module.css +63 -0
  5. package/dist/QuantityStepper.module.css +67 -0
  6. package/dist/SuggestionInput.module.css +103 -0
  7. package/dist/index.d.ts +128 -2
  8. package/dist/index.js +1007 -169
  9. package/package.json +1 -1
  10. package/src/components/CheckableListRow/CheckableListRow.module.css +95 -0
  11. package/src/components/CheckableListRow/CheckableListRow.stories.tsx +99 -0
  12. package/src/components/CheckableListRow/CheckableListRow.tsx +89 -0
  13. package/src/components/Dialog/Dialog.module.css +12 -12
  14. package/src/components/Icon/icons/apple.tsx +21 -0
  15. package/src/components/Icon/icons/banana.tsx +21 -0
  16. package/src/components/Icon/icons/beef.tsx +22 -0
  17. package/src/components/Icon/icons/beer.tsx +24 -0
  18. package/src/components/Icon/icons/candy.tsx +24 -0
  19. package/src/components/Icon/icons/carrot.tsx +22 -0
  20. package/src/components/Icon/icons/coffee.tsx +23 -0
  21. package/src/components/Icon/icons/cookie.tsx +25 -0
  22. package/src/components/Icon/icons/croissant.tsx +24 -0
  23. package/src/components/Icon/icons/cup-soda.tsx +23 -0
  24. package/src/components/Icon/icons/drumstick.tsx +21 -0
  25. package/src/components/Icon/icons/egg.tsx +20 -0
  26. package/src/components/Icon/icons/fish.tsx +25 -0
  27. package/src/components/Icon/icons/index.ts +81 -1
  28. package/src/components/Icon/icons/milk.tsx +22 -0
  29. package/src/components/Icon/icons/pizza.tsx +24 -0
  30. package/src/components/Icon/icons/salad.tsx +24 -0
  31. package/src/components/Icon/icons/shopping-basket.tsx +26 -0
  32. package/src/components/Icon/icons/snowflake.tsx +31 -0
  33. package/src/components/Icon/icons/spray-can.tsx +29 -0
  34. package/src/components/Icon/icons/wine.tsx +23 -0
  35. package/src/components/IconPicker/IconPicker.module.css +63 -0
  36. package/src/components/IconPicker/IconPicker.stories.tsx +84 -0
  37. package/src/components/IconPicker/IconPicker.tsx +90 -0
  38. package/src/components/QuantityStepper/QuantityStepper.module.css +67 -0
  39. package/src/components/QuantityStepper/QuantityStepper.stories.tsx +79 -0
  40. package/src/components/QuantityStepper/QuantityStepper.tsx +107 -0
  41. package/src/components/SuggestionInput/SuggestionInput.module.css +103 -0
  42. package/src/components/SuggestionInput/SuggestionInput.stories.tsx +144 -0
  43. package/src/components/SuggestionInput/SuggestionInput.tsx +207 -0
  44. package/src/index.ts +11 -0
  45. package/src/stories/DesignSystemOverview.stories.tsx +107 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sovereignfs/ui",
3
- "version": "0.33.0",
3
+ "version": "0.37.0",
4
4
  "type": "module",
5
5
  "description": "Sovereign Design System — design tokens and React components.",
6
6
  "keywords": [
@@ -0,0 +1,95 @@
1
+ .row {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: var(--sv-space-3);
5
+ width: 100%;
6
+ }
7
+
8
+ .tapTarget {
9
+ display: flex;
10
+ align-items: center;
11
+ gap: var(--sv-space-2);
12
+ flex: 1;
13
+ min-width: 0;
14
+ min-height: var(--sv-touch-target-min);
15
+ cursor: pointer;
16
+ }
17
+
18
+ .tapTarget:focus-visible {
19
+ outline: 2px solid var(--sv-color-focus-ring);
20
+ outline-offset: 2px;
21
+ border-radius: var(--sv-radius-sm);
22
+ }
23
+
24
+ /* Visual box — matches Checkbox.module.css's .box/.checked/.tick. */
25
+ .box {
26
+ --checkbox-box-size: 18px;
27
+ flex-shrink: 0;
28
+ width: var(--checkbox-box-size);
29
+ height: var(--checkbox-box-size);
30
+ border-radius: var(--sv-radius-sm);
31
+ border: 1.5px solid var(--sv-color-border-strong);
32
+ background: var(--sv-color-surface);
33
+ transition:
34
+ background-color 0.15s ease,
35
+ border-color 0.15s ease;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ }
40
+
41
+ .checked {
42
+ background-color: var(--sv-color-accent);
43
+ border-color: var(--sv-color-accent);
44
+ color: var(--sv-white);
45
+ }
46
+
47
+ .tick {
48
+ width: 10px;
49
+ height: 8px;
50
+ pointer-events: none;
51
+ }
52
+
53
+ .icon {
54
+ display: flex;
55
+ align-items: center;
56
+ flex-shrink: 0;
57
+ color: var(--sv-color-text-muted);
58
+ }
59
+
60
+ .label {
61
+ flex: 1;
62
+ min-width: 0;
63
+ font-size: var(--sv-font-size-sm);
64
+ color: var(--sv-color-text-primary);
65
+ overflow: hidden;
66
+ text-overflow: ellipsis;
67
+ white-space: nowrap;
68
+ transition: color 0.15s ease;
69
+ position: relative;
70
+ }
71
+
72
+ .label::after {
73
+ content: '';
74
+ position: absolute;
75
+ left: 0;
76
+ top: 50%;
77
+ width: 100%;
78
+ height: 1.5px;
79
+ background: var(--sv-color-text-muted);
80
+ transform: scaleX(0);
81
+ transform-origin: left center;
82
+ transition: transform 0.2s ease;
83
+ }
84
+
85
+ .struck {
86
+ color: var(--sv-color-text-muted);
87
+ }
88
+
89
+ .struck::after {
90
+ transform: scaleX(1);
91
+ }
92
+
93
+ .trailing {
94
+ flex-shrink: 0;
95
+ }
@@ -0,0 +1,99 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import { CheckableListRow } from './CheckableListRow';
4
+ import { Icon } from '../Icon/Icon';
5
+
6
+ const meta = {
7
+ title: 'Components/CheckableListRow',
8
+ component: CheckableListRow,
9
+ parameters: {
10
+ layout: 'padded',
11
+ docs: {
12
+ description: {
13
+ component:
14
+ 'A whole-row tap target that toggles a checked state, with strike-through on the label when checked — for "tap the row to mark it done" lists.',
15
+ },
16
+ },
17
+ },
18
+ args: {
19
+ checked: false,
20
+ onCheckedChange: () => {},
21
+ label: 'Bananas',
22
+ },
23
+ } satisfies Meta<typeof CheckableListRow>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ function ControlledRow({
29
+ initial = false,
30
+ icon,
31
+ trailing,
32
+ disabled,
33
+ }: {
34
+ initial?: boolean;
35
+ icon?: boolean;
36
+ trailing?: boolean;
37
+ disabled?: boolean;
38
+ }) {
39
+ const [checked, setChecked] = useState(initial);
40
+ return (
41
+ <div style={{ width: 320 }}>
42
+ <CheckableListRow
43
+ checked={checked}
44
+ onCheckedChange={setChecked}
45
+ label="Bananas"
46
+ icon={icon ? <Icon name="banana" size="md" aria-hidden /> : undefined}
47
+ trailing={trailing ? <span style={{ fontSize: 13, color: '#888' }}>6 pcs</span> : undefined}
48
+ disabled={disabled}
49
+ />
50
+ </div>
51
+ );
52
+ }
53
+
54
+ export const Default: Story = {
55
+ render: () => <ControlledRow />,
56
+ };
57
+
58
+ export const Checked: Story = {
59
+ render: () => <ControlledRow initial />,
60
+ };
61
+
62
+ export const WithIconAndTrailing: Story = {
63
+ render: () => <ControlledRow icon trailing />,
64
+ };
65
+
66
+ export const CheckedWithIconAndTrailing: Story = {
67
+ render: () => <ControlledRow initial icon trailing />,
68
+ };
69
+
70
+ export const Disabled: Story = {
71
+ render: () => <ControlledRow icon trailing disabled />,
72
+ };
73
+
74
+ export const List: Story = {
75
+ name: 'Multiple rows (list context)',
76
+ render: () => {
77
+ const items = ['Bananas', 'Milk', 'Eggs', 'Coffee'];
78
+ const [checkedSet, setCheckedSet] = useState<Set<string>>(new Set(['Milk']));
79
+ return (
80
+ <div style={{ width: 320, display: 'flex', flexDirection: 'column', gap: 4 }}>
81
+ {items.map((item) => (
82
+ <CheckableListRow
83
+ key={item}
84
+ checked={checkedSet.has(item)}
85
+ onCheckedChange={(checked) =>
86
+ setCheckedSet((prev) => {
87
+ const next = new Set(prev);
88
+ if (checked) next.add(item);
89
+ else next.delete(item);
90
+ return next;
91
+ })
92
+ }
93
+ label={item}
94
+ />
95
+ ))}
96
+ </div>
97
+ );
98
+ },
99
+ };
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+
3
+ import type { KeyboardEvent, ReactNode } from 'react';
4
+ import styles from './CheckableListRow.module.css';
5
+
6
+ export interface CheckableListRowProps {
7
+ checked: boolean;
8
+ onCheckedChange: (checked: boolean) => void;
9
+ label: string;
10
+ /** Leading icon, e.g. a per-item `<Icon>`. */
11
+ icon?: ReactNode;
12
+ /** Trailing content, e.g. a quantity, a `QuantityStepper`, or a badge. */
13
+ trailing?: ReactNode;
14
+ disabled?: boolean;
15
+ className?: string;
16
+ }
17
+
18
+ /**
19
+ * CheckableListRow — a whole-row tap target that toggles a checked state,
20
+ * with strike-through on the label when checked. Built for "tap the row to
21
+ * mark it done" lists (Sovereign Shopper's tap-to-buy, SHP-07) where the
22
+ * checkbox itself is too small a target on mobile and the row already has
23
+ * nothing else competing for the tap.
24
+ *
25
+ * Renders as `role="checkbox"` on the row itself rather than composing
26
+ * `Checkbox`'s native `<input>` — nesting a real checkbox input inside the
27
+ * row's own click handler would mean two overlapping interactive elements
28
+ * (invalid HTML, and the input's own click would double-fire the row's
29
+ * toggle). The visual box matches `Checkbox`'s styling for consistency.
30
+ *
31
+ * `trailing` content (e.g. a `QuantityStepper`) is rendered outside the
32
+ * `role="checkbox"` element so its own interactive controls (+/- buttons)
33
+ * don't sit inside another interactive element either — clicking those
34
+ * doesn't toggle the row.
35
+ */
36
+ export function CheckableListRow({
37
+ checked,
38
+ onCheckedChange,
39
+ label,
40
+ icon,
41
+ trailing,
42
+ disabled = false,
43
+ className,
44
+ }: CheckableListRowProps) {
45
+ function toggle() {
46
+ if (!disabled) onCheckedChange(!checked);
47
+ }
48
+
49
+ function handleKeyDown(e: KeyboardEvent<HTMLDivElement>) {
50
+ if (e.key === ' ' || e.key === 'Enter') {
51
+ e.preventDefault();
52
+ toggle();
53
+ }
54
+ }
55
+
56
+ return (
57
+ <div className={[styles.row, className].filter(Boolean).join(' ')}>
58
+ <div
59
+ role="checkbox"
60
+ aria-checked={checked}
61
+ aria-label={label}
62
+ aria-disabled={disabled || undefined}
63
+ tabIndex={disabled ? -1 : 0}
64
+ className={styles.tapTarget}
65
+ onClick={toggle}
66
+ onKeyDown={handleKeyDown}
67
+ >
68
+ <span className={[styles.box, checked ? styles.checked : ''].filter(Boolean).join(' ')}>
69
+ {checked && (
70
+ <svg className={styles.tick} viewBox="0 0 10 8" fill="none" aria-hidden="true">
71
+ <path
72
+ d="M1 4l3 3 5-6"
73
+ stroke="currentColor"
74
+ strokeWidth="1.5"
75
+ strokeLinecap="round"
76
+ strokeLinejoin="round"
77
+ />
78
+ </svg>
79
+ )}
80
+ </span>
81
+ {icon && <span className={styles.icon}>{icon}</span>}
82
+ <span className={[styles.label, checked ? styles.struck : ''].filter(Boolean).join(' ')}>
83
+ {label}
84
+ </span>
85
+ </div>
86
+ {trailing && <span className={styles.trailing}>{trailing}</span>}
87
+ </div>
88
+ );
89
+ }
@@ -205,19 +205,19 @@
205
205
 
206
206
  /* Title + close button in one solid row, via the shared OverlayHeader
207
207
  component. Being a flex sibling before .content means it never scrolls —
208
- the content area scrolls below it. */
208
+ the content area scrolls below it.
209
+ .content itself needs no mobile override here any more: it used to zero
210
+ out padding-top so a plugin's hand-rolled sticky header (rendered as
211
+ .content's own first child, right below OverlayHeader) would sit flush
212
+ against it. That case no longer exists — a plugin with a tab strip/
213
+ secondary nav now hands it to OverlayHeader's own secondRow slot
214
+ (useOverlaySecondRow) instead of rendering it inside .content; Account
215
+ and Console both migrated to this (mobile design-system plan, Phase
216
+ C1b). With .content's first child back to being genuine page content, it
217
+ needs the same breathing room from the header that .content's own base
218
+ padding (var(--sv-space-6) on every side) already provides everywhere
219
+ else. */
209
220
  .mobileHeader {
210
221
  display: block;
211
222
  }
212
-
213
- /* Remove top padding so the sticky plugin header sits flush against
214
- OverlayHeader — no gap for scrolling content to bleed through.
215
- padding-bottom no longer adds --sv-shell-footer-height on top of
216
- --sv-space-6 — the scrim above already stops short of the footer, so
217
- .content doesn't need to additionally compensate for it here (that used
218
- to double-count the footer clearance). */
219
- .content {
220
- padding-top: 0;
221
- padding-bottom: var(--sv-space-6, 24px);
222
- }
223
223
  }
@@ -0,0 +1,21 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function AppleIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M12 6.528V3a1 1 0 0 1 1-1h0" />
18
+ <path d="M18.237 21A15 15 0 0 0 22 11a6 6 0 0 0-10-4.472A6 6 0 0 0 2 11a15.1 15.1 0 0 0 3.763 10 3 3 0 0 0 3.648.648 5.5 5.5 0 0 1 5.178 0A3 3 0 0 0 18.237 21" />
19
+ </svg>
20
+ );
21
+ }
@@ -0,0 +1,21 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function BananaIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M4 13c3.5-2 8-2 10 2a5.5 5.5 0 0 1 8 5" />
18
+ <path d="M5.15 17.89c5.52-1.52 8.65-6.89 7-12C11.55 4 11.5 2 13 2c3.22 0 5 5.5 5 8 0 6.5-4.2 12-10.49 12C5.11 22 2 22 2 20c0-1.5 1.14-1.55 3.15-2.11Z" />
19
+ </svg>
20
+ );
21
+ }
@@ -0,0 +1,22 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function BeefIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M16.4 13.7A6.5 6.5 0 1 0 6.28 6.6c-1.1 3.13-.78 3.9-3.18 6.08A3 3 0 0 0 5 18c4 0 8.4-1.8 11.4-4.3" />
18
+ <path d="m18.5 6 2.19 4.5a6.48 6.48 0 0 1-2.29 7.2C15.4 20.2 11 22 7 22a3 3 0 0 1-2.68-1.66L2.4 16.5" />
19
+ <circle cx="12.5" cy="8.5" r="2.5" />
20
+ </svg>
21
+ );
22
+ }
@@ -0,0 +1,24 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function BeerIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M17 11h1a3 3 0 0 1 0 6h-1" />
18
+ <path d="M9 12v6" />
19
+ <path d="M13 12v6" />
20
+ <path d="M14 7.5c-1 0-1.44.5-3 .5s-2-.5-3-.5-1.72.5-2.5.5a2.5 2.5 0 0 1 0-5c.78 0 1.57.5 2.5.5S9.44 2 11 2s2 1.5 3 1.5 1.72-.5 2.5-.5a2.5 2.5 0 0 1 0 5c-.78 0-1.5-.5-2.5-.5Z" />
21
+ <path d="M5 8v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V8" />
22
+ </svg>
23
+ );
24
+ }
@@ -0,0 +1,24 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CandyIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M10 7v10.9" />
18
+ <path d="M14 6.1V17" />
19
+ <path d="M16 7V3a1 1 0 0 1 1.707-.707 2.5 2.5 0 0 0 2.152.717 1 1 0 0 1 1.131 1.131 2.5 2.5 0 0 0 .717 2.152A1 1 0 0 1 21 8h-4" />
20
+ <path d="M16.536 7.465a5 5 0 0 0-7.072 0l-2 2a5 5 0 0 0 0 7.07 5 5 0 0 0 7.072 0l2-2a5 5 0 0 0 0-7.07" />
21
+ <path d="M8 17v4a1 1 0 0 1-1.707.707 2.5 2.5 0 0 0-2.152-.717 1 1 0 0 1-1.131-1.131 2.5 2.5 0 0 0-.717-2.152A1 1 0 0 1 3 16h4" />
22
+ </svg>
23
+ );
24
+ }
@@ -0,0 +1,22 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CarrotIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M2.27 21.7s9.87-3.5 12.73-6.36a4.5 4.5 0 0 0-6.36-6.37C5.77 11.84 2.27 21.7 2.27 21.7zM8.64 14l-2.05-2.04M15.34 15l-2.46-2.46" />
18
+ <path d="M22 9s-1.33-2-3.5-2C16.86 7 15 9 15 9s1.33 2 3.5 2S22 9 22 9z" />
19
+ <path d="M15 2s-2 1.33-2 3.5S15 9 15 9s2-1.84 2-3.5C17 3.33 15 2 15 2z" />
20
+ </svg>
21
+ );
22
+ }
@@ -0,0 +1,23 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CoffeeIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M10 2v2" />
18
+ <path d="M14 2v2" />
19
+ <path d="M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1" />
20
+ <path d="M6 2v2" />
21
+ </svg>
22
+ );
23
+ }
@@ -0,0 +1,25 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CookieIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5" />
18
+ <path d="M8.5 8.5v.01" />
19
+ <path d="M16 15.5v.01" />
20
+ <path d="M12 12v.01" />
21
+ <path d="M11 17v.01" />
22
+ <path d="M7 14v.01" />
23
+ </svg>
24
+ );
25
+ }
@@ -0,0 +1,24 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CroissantIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M10.2 18H4.774a1.5 1.5 0 0 1-1.352-.97 11 11 0 0 1 .132-6.487" />
18
+ <path d="M18 10.2V4.774a1.5 1.5 0 0 0-.97-1.352 11 11 0 0 0-6.486.132" />
19
+ <path d="M18 5a4 3 0 0 1 4 3 2 2 0 0 1-2 2 10 10 0 0 0-5.139 1.42" />
20
+ <path d="M5 18a3 4 0 0 0 3 4 2 2 0 0 0 2-2 10 10 0 0 1 1.42-5.14" />
21
+ <path d="M8.709 2.554a10 10 0 0 0-6.155 6.155 1.5 1.5 0 0 0 .676 1.626l9.807 5.42a2 2 0 0 0 2.718-2.718l-5.42-9.807a1.5 1.5 0 0 0-1.626-.676" />
22
+ </svg>
23
+ );
24
+ }
@@ -0,0 +1,23 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function CupSodaIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="m6 8 1.75 12.28a2 2 0 0 0 2 1.72h4.54a2 2 0 0 0 2-1.72L18 8" />
18
+ <path d="M5 8h14" />
19
+ <path d="M7 15a6.47 6.47 0 0 1 5 0 6.47 6.47 0 0 0 5 0" />
20
+ <path d="m12 8 1-6h2" />
21
+ </svg>
22
+ );
23
+ }
@@ -0,0 +1,21 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function DrumstickIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M15.4 15.63a7.875 6 135 1 1 6.23-6.23 4.5 3.43 135 0 0-6.23 6.23" />
18
+ <path d="m8.29 12.71-2.6 2.6a2.5 2.5 0 1 0-1.65 4.65A2.5 2.5 0 1 0 8.7 18.3l2.59-2.59" />
19
+ </svg>
20
+ );
21
+ }
@@ -0,0 +1,20 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function EggIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M12 2C8 2 4 8 4 14a8 8 0 0 0 16 0c0-6-4-12-8-12" />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,25 @@
1
+ // Generated by scripts/generate-icons.ts — do not edit.
2
+ // Source: Lucide (https://lucide.dev) — ISC license, see packages/ui/NOTICE.
3
+ import type { SVGProps } from 'react';
4
+
5
+ export function FishIcon(props: SVGProps<SVGSVGElement>) {
6
+ return (
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ {...props}
16
+ >
17
+ <path d="M6.5 12c.94-3.46 4.94-6 8.5-6 3.56 0 6.06 2.54 7 6-.94 3.47-3.44 6-7 6s-7.56-2.53-8.5-6Z" />
18
+ <path d="M18 12v.5" />
19
+ <path d="M16 17.93a9.77 9.77 0 0 1 0-11.86" />
20
+ <path d="M7 10.67C7 8 5.58 5.97 2.73 5.5c-1 1.5-1 5 .23 6.5-1.24 1.5-1.24 5-.23 6.5C5.58 18.03 7 16 7 13.33" />
21
+ <path d="M10.46 7.26C10.2 5.88 9.17 4.24 8 3h5.8a2 2 0 0 1 1.98 1.67l.23 1.4" />
22
+ <path d="m16.01 17.93-.23 1.4A2 2 0 0 1 13.8 21H9.5a5.96 5.96 0 0 0 1.49-3.98" />
23
+ </svg>
24
+ );
25
+ }