@bearmenu/ui 0.8.32 → 0.8.34
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.
- package/dist/{chunk-5HHRVJOT.js → chunk-5SGKGFMN.js} +1 -1
- package/dist/{chunk-GESB7GCF.js → chunk-6W25S5CF.js} +1 -1
- package/dist/chunk-LY67SOFC.js +142 -0
- package/dist/{chunk-ZU4NAYN7.js → chunk-NIAL4ZU2.js} +13 -1
- package/dist/{chunk-JWTN7MNK.js → chunk-TVEIUTBQ.js} +2 -2
- package/dist/{chunk-ZJMCU7MI.js → chunk-VCRXL7H5.js} +1 -1
- package/dist/chunk-XLHMF6F5.js +127 -0
- package/dist/{chunk-VSRGEB36.js → chunk-XNBDACL7.js} +1 -1
- package/dist/components/action-bar.d.ts +67 -0
- package/dist/components/action-bar.js +43 -0
- package/dist/components/activity-row.d.ts +38 -0
- package/dist/components/activity-row.js +43 -0
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/avatar.d.ts +4 -1
- package/dist/components/avatar.js +39 -5
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/booking-row.js +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +1 -1
- package/dist/components/calendar.js +1 -1
- package/dist/components/carousel.js +1 -1
- package/dist/components/coach-marks.js +1 -1
- package/dist/components/combobox.js +3 -3
- package/dist/components/command.d.ts +15 -15
- package/dist/components/command.js +2 -2
- package/dist/components/concept-convergence.js +2 -2
- package/dist/components/currency-input.js +4 -142
- package/dist/components/dialog.d.ts +6 -0
- package/dist/components/dialog.js +1 -1
- package/dist/components/drawer.d.ts +6 -0
- package/dist/components/drawer.js +3 -127
- package/dist/components/empty-state.d.ts +2 -2
- package/dist/components/empty-state.js +1 -1
- package/dist/components/event-detail-panel.js +1 -1
- package/dist/components/event-list-row-wide.js +1 -1
- package/dist/components/filter-category-row.js +1 -1
- package/dist/components/hold-countdown.js +1 -1
- package/dist/components/link-button.js +1 -1
- package/dist/components/menu-family-block.js +1 -1
- package/dist/components/menu-index-list.js +1 -1
- package/dist/components/menu-item.js +3 -3
- package/dist/components/menu-pick-row.d.ts +47 -0
- package/dist/components/menu-pick-row.js +49 -0
- package/dist/components/multi-select-combobox.js +4 -4
- package/dist/components/pagination.js +1 -1
- package/dist/components/place-card.js +1 -1
- package/dist/components/place-details-mobile.js +1 -1
- package/dist/components/qr-panel.d.ts +31 -0
- package/dist/components/qr-panel.js +33 -0
- package/dist/components/reconcile-bar.d.ts +47 -0
- package/dist/components/reconcile-bar.js +60 -0
- package/dist/components/responsive-overlay.d.ts +59 -0
- package/dist/components/responsive-overlay.js +132 -0
- package/dist/components/searchable-select.js +3 -3
- package/dist/components/signature-chip.js +2 -2
- package/dist/components/sliding-panels.js +1 -1
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/split-share-row.d.ts +77 -0
- package/dist/components/split-share-row.js +101 -0
- package/dist/components/table-ledger-card.d.ts +80 -0
- package/dist/components/table-ledger-card.js +84 -0
- package/dist/components/table-trigger-band.d.ts +56 -0
- package/dist/components/table-trigger-band.js +43 -0
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/text.d.ts +2 -2
- package/dist/components/toggle.d.ts +1 -1
- package/dist/components/top-ranking-entry.js +3 -3
- package/dist/components/venue-events-block.js +1 -1
- package/package.json +10 -1
- package/src/components/action-bar.stories.tsx +78 -0
- package/src/components/action-bar.tsx +80 -0
- package/src/components/activity-row.stories.tsx +78 -0
- package/src/components/activity-row.tsx +65 -0
- package/src/components/avatar.stories.tsx +55 -0
- package/src/components/avatar.tsx +63 -19
- package/src/components/badge.stories.tsx +41 -0
- package/src/components/badge.tsx +13 -0
- package/src/components/button.tsx +1 -1
- package/src/components/dialog.tsx +8 -2
- package/src/components/drawer.tsx +8 -2
- package/src/components/hold-countdown.tsx +1 -1
- package/src/components/menu-pick-row.stories.tsx +71 -0
- package/src/components/menu-pick-row.tsx +76 -0
- package/src/components/qr-panel.stories.tsx +39 -0
- package/src/components/qr-panel.tsx +52 -0
- package/src/components/reconcile-bar.stories.tsx +57 -0
- package/src/components/reconcile-bar.tsx +80 -0
- package/src/components/responsive-overlay.stories.tsx +91 -0
- package/src/components/responsive-overlay.test.tsx +162 -0
- package/src/components/responsive-overlay.tsx +232 -0
- package/src/components/shared-table-primitives.test.tsx +482 -0
- package/src/components/split-share-row.stories.tsx +114 -0
- package/src/components/split-share-row.tsx +150 -0
- package/src/components/table-ledger-card.stories.tsx +120 -0
- package/src/components/table-ledger-card.tsx +138 -0
- package/src/components/table-trigger-band.stories.tsx +76 -0
- package/src/components/table-trigger-band.tsx +75 -0
- package/src/globals.css +62 -0
- package/src/test/setup.ts +11 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CurrencyInput } from '../chunk-LY67SOFC.js';
|
|
2
|
+
import '../chunk-GTQSGDYF.js';
|
|
3
|
+
import { Checkbox } from '../chunk-L3CDXVEP.js';
|
|
4
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
5
|
+
import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var SplitShareRow = React.forwardRef(
|
|
10
|
+
(_a, ref) => {
|
|
11
|
+
var _b = _a, {
|
|
12
|
+
className,
|
|
13
|
+
person,
|
|
14
|
+
amount,
|
|
15
|
+
editable = false,
|
|
16
|
+
amountValue = null,
|
|
17
|
+
onAmountChange,
|
|
18
|
+
currency = "lei",
|
|
19
|
+
locale,
|
|
20
|
+
checked,
|
|
21
|
+
onCheckedChange,
|
|
22
|
+
includeLabel,
|
|
23
|
+
amountLabel,
|
|
24
|
+
disabled = false
|
|
25
|
+
} = _b, props = __objRest(_b, [
|
|
26
|
+
"className",
|
|
27
|
+
"person",
|
|
28
|
+
"amount",
|
|
29
|
+
"editable",
|
|
30
|
+
"amountValue",
|
|
31
|
+
"onAmountChange",
|
|
32
|
+
"currency",
|
|
33
|
+
"locale",
|
|
34
|
+
"checked",
|
|
35
|
+
"onCheckedChange",
|
|
36
|
+
"includeLabel",
|
|
37
|
+
"amountLabel",
|
|
38
|
+
"disabled"
|
|
39
|
+
]);
|
|
40
|
+
const amountId = React.useId();
|
|
41
|
+
return /* @__PURE__ */ jsxs(
|
|
42
|
+
"div",
|
|
43
|
+
__spreadProps(__spreadValues({
|
|
44
|
+
ref,
|
|
45
|
+
"data-slot": "split-share-row",
|
|
46
|
+
"data-checked": checked ? "" : void 0,
|
|
47
|
+
className: cn(
|
|
48
|
+
"flex items-center gap-3 rounded-xl border border-border bg-card px-3 py-2.5",
|
|
49
|
+
className
|
|
50
|
+
)
|
|
51
|
+
}, props), {
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 order-2", children: person }),
|
|
54
|
+
editable ? /* @__PURE__ */ jsxs("span", { className: "order-3 shrink-0", children: [
|
|
55
|
+
/* @__PURE__ */ jsx("label", { htmlFor: amountId, className: "sr-only", children: amountLabel }),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
CurrencyInput,
|
|
58
|
+
{
|
|
59
|
+
id: amountId,
|
|
60
|
+
value: amountValue,
|
|
61
|
+
onChange: (next) => onAmountChange == null ? void 0 : onAmountChange(next),
|
|
62
|
+
currency,
|
|
63
|
+
locale,
|
|
64
|
+
disabled,
|
|
65
|
+
className: "h-9 w-24 rounded-lg border border-border bg-surface-2 text-right text-[13px] font-bold tabular-nums focus-within:ring-2 focus-within:ring-ring"
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
] }) : /* @__PURE__ */ jsx(
|
|
69
|
+
"span",
|
|
70
|
+
{
|
|
71
|
+
"data-slot": "split-share-amount",
|
|
72
|
+
className: cn(
|
|
73
|
+
"order-3 shrink-0 rounded-lg bg-surface-2 px-2.5 py-1 text-[13px] font-bold tabular-nums md:bg-transparent md:px-0",
|
|
74
|
+
// Only the amount goes quiet when someone is out of the split.
|
|
75
|
+
// Dimming the whole row takes the name under 4.5:1 with it.
|
|
76
|
+
checked === false && "text-muted-foreground"
|
|
77
|
+
),
|
|
78
|
+
children: amount
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
onCheckedChange ? /* @__PURE__ */ jsx(
|
|
82
|
+
Checkbox,
|
|
83
|
+
{
|
|
84
|
+
checked,
|
|
85
|
+
onCheckedChange: (next) => onCheckedChange(next === true),
|
|
86
|
+
disabled,
|
|
87
|
+
"aria-label": includeLabel,
|
|
88
|
+
className: cn(
|
|
89
|
+
"relative order-4 size-6 rounded-full md:order-1 md:size-5 md:rounded-md",
|
|
90
|
+
"before:absolute before:-inset-2.5 before:content-[''] md:before:-inset-3"
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
) : null
|
|
94
|
+
]
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
SplitShareRow.displayName = "SplitShareRow";
|
|
100
|
+
|
|
101
|
+
export { SplitShareRow };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TableLedgerCard — what one party at a shared table has against their name.
|
|
7
|
+
*
|
|
8
|
+
* The board draws this shape four times and it is one component
|
|
9
|
+
* (16-shared-table.html):
|
|
10
|
+
* - T2, a person's card — avatar, "Adrian · host", "2 items + share", their
|
|
11
|
+
* total, and the items under it.
|
|
12
|
+
* - T2, the Shared card — the same card whose `lead` is a people glyph or an
|
|
13
|
+
* `AvatarGroup` instead of one avatar, and whose rows carry "40 lei each".
|
|
14
|
+
* - X5, the same card the moment someone else changed it: `updated` rings it
|
|
15
|
+
* and tints the header, so a remote write is marked in place and the ledger
|
|
16
|
+
* never silently re-sorts under a reader.
|
|
17
|
+
* - T4 desktop, the drop targets — the header alone, no rows, `drop-idle`
|
|
18
|
+
* until a drag is over it and `drop-active` while it is.
|
|
19
|
+
*
|
|
20
|
+
* Money slots are `font-bold tabular-nums`, so a column of totals lines up and
|
|
21
|
+
* does not shuffle when one changes. The board sets the NUMERAL in the bold
|
|
22
|
+
* sans and only the currency suffix in mono, small and muted — so a caller
|
|
23
|
+
* passes `96` followed by a `font-mono text-[11px] text-muted-foreground`
|
|
24
|
+
* "lei", and never wraps the whole amount in `font-mono`.
|
|
25
|
+
*
|
|
26
|
+
* Drag is an accelerator only. A card in `drop-active` must have a tap and
|
|
27
|
+
* keyboard path to the same outcome — every T4 row opens "Who had this?" —
|
|
28
|
+
* because a pointer that can drag is not a pointer everyone has.
|
|
29
|
+
*/
|
|
30
|
+
declare const tableLedgerCardVariants: (props?: ({
|
|
31
|
+
state?: "default" | "updated" | "drop-idle" | "drop-active" | null | undefined;
|
|
32
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
33
|
+
type TableLedgerRow = {
|
|
34
|
+
/** React key. Falls back to the index when the caller has no id. */
|
|
35
|
+
id?: string;
|
|
36
|
+
/** The dish or drink. */
|
|
37
|
+
label: React.ReactNode;
|
|
38
|
+
/** Its price, formatted by the caller. */
|
|
39
|
+
amount: React.ReactNode;
|
|
40
|
+
/** The quiet trailing line — "40 lei each" on the Shared card. Replaces `amount` when set. */
|
|
41
|
+
trailing?: React.ReactNode;
|
|
42
|
+
/** A chip on the row — "just now" on the X5 card, "Queued" on X6. */
|
|
43
|
+
badge?: React.ReactNode;
|
|
44
|
+
};
|
|
45
|
+
type TableLedgerCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & VariantProps<typeof tableLedgerCardVariants> & {
|
|
46
|
+
/** The leading slot: an `Avatar`, an `AvatarGroup`, or a glyph for "Shared". */
|
|
47
|
+
lead?: React.ReactNode;
|
|
48
|
+
/** The name — "Adrian · host", "Shared between everyone". */
|
|
49
|
+
person?: React.ReactNode;
|
|
50
|
+
/** The line under the name — "2 items + share". */
|
|
51
|
+
meta?: React.ReactNode;
|
|
52
|
+
/** Their running total, formatted by the caller. */
|
|
53
|
+
total?: React.ReactNode;
|
|
54
|
+
/** The items. Empty or omitted for a T4 drop target. */
|
|
55
|
+
rows?: TableLedgerRow[];
|
|
56
|
+
/** Accessible names. Injected; the design system holds no copy. */
|
|
57
|
+
labels?: {
|
|
58
|
+
rows?: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
declare const TableLedgerCard: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & VariantProps<(props?: ({
|
|
62
|
+
state?: "default" | "updated" | "drop-idle" | "drop-active" | null | undefined;
|
|
63
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
64
|
+
/** The leading slot: an `Avatar`, an `AvatarGroup`, or a glyph for "Shared". */
|
|
65
|
+
lead?: React.ReactNode;
|
|
66
|
+
/** The name — "Adrian · host", "Shared between everyone". */
|
|
67
|
+
person?: React.ReactNode;
|
|
68
|
+
/** The line under the name — "2 items + share". */
|
|
69
|
+
meta?: React.ReactNode;
|
|
70
|
+
/** Their running total, formatted by the caller. */
|
|
71
|
+
total?: React.ReactNode;
|
|
72
|
+
/** The items. Empty or omitted for a T4 drop target. */
|
|
73
|
+
rows?: TableLedgerRow[];
|
|
74
|
+
/** Accessible names. Injected; the design system holds no copy. */
|
|
75
|
+
labels?: {
|
|
76
|
+
rows?: string;
|
|
77
|
+
};
|
|
78
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
79
|
+
|
|
80
|
+
export { TableLedgerCard, type TableLedgerCardProps, type TableLedgerRow, tableLedgerCardVariants };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var tableLedgerCardVariants = cva(
|
|
8
|
+
"overflow-hidden rounded-2xl border bg-card transition-colors",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
state: {
|
|
12
|
+
default: "border-border",
|
|
13
|
+
updated: "border-primary",
|
|
14
|
+
"drop-idle": "border-dashed border-border",
|
|
15
|
+
"drop-active": "border-dashed border-primary bg-accent-subtle"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: { state: "default" }
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
var TableLedgerCard = React.forwardRef(
|
|
22
|
+
(_a, ref) => {
|
|
23
|
+
var _b = _a, { className, state, lead, person, meta, total, rows, labels } = _b, props = __objRest(_b, ["className", "state", "lead", "person", "meta", "total", "rows", "labels"]);
|
|
24
|
+
return /* @__PURE__ */ jsxs(
|
|
25
|
+
"div",
|
|
26
|
+
__spreadProps(__spreadValues({
|
|
27
|
+
ref,
|
|
28
|
+
"data-slot": "table-ledger-card",
|
|
29
|
+
"data-state": state != null ? state : "default",
|
|
30
|
+
className: cn(tableLedgerCardVariants({ state }), className)
|
|
31
|
+
}, props), {
|
|
32
|
+
children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(
|
|
34
|
+
"div",
|
|
35
|
+
{
|
|
36
|
+
"data-slot": "table-ledger-header",
|
|
37
|
+
className: cn(
|
|
38
|
+
"flex items-center gap-3 px-3.5 py-3",
|
|
39
|
+
// The header takes its own ground only when there are items under it,
|
|
40
|
+
// so it reads as their heading. A card with no rows — a drop target,
|
|
41
|
+
// a person who has had nothing yet — is one plain block, and tinting
|
|
42
|
+
// it would also paint over `drop-active`'s accent.
|
|
43
|
+
(rows == null ? void 0 : rows.length) ? state === "updated" ? "bg-accent-subtle" : "bg-surface-2/60" : void 0
|
|
44
|
+
),
|
|
45
|
+
children: [
|
|
46
|
+
lead ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: lead }) : null,
|
|
47
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
48
|
+
person ? /* @__PURE__ */ jsx("div", { className: "truncate text-[15px] font-bold leading-tight", children: person }) : null,
|
|
49
|
+
meta ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate text-[12.5px] text-muted-foreground", children: meta }) : null
|
|
50
|
+
] }),
|
|
51
|
+
total ? /* @__PURE__ */ jsx(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
"data-slot": "table-ledger-total",
|
|
55
|
+
className: "shrink-0 text-[15px] font-bold tabular-nums",
|
|
56
|
+
children: total
|
|
57
|
+
}
|
|
58
|
+
) : null
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
rows && rows.length > 0 ? /* @__PURE__ */ jsx("ul", { "data-slot": "table-ledger-rows", "aria-label": labels == null ? void 0 : labels.rows, className: "divide-y divide-border", children: rows.map((row, index) => {
|
|
63
|
+
var _a2;
|
|
64
|
+
return /* @__PURE__ */ jsxs(
|
|
65
|
+
"li",
|
|
66
|
+
{
|
|
67
|
+
className: "flex items-center gap-3 px-3.5 py-2.5 text-[14px]",
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: row.label }),
|
|
70
|
+
row.badge,
|
|
71
|
+
row.trailing ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[12.5px] text-muted-foreground", children: row.trailing }) : /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[14px] font-bold tabular-nums", children: row.amount })
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
(_a2 = row.id) != null ? _a2 : index
|
|
75
|
+
);
|
|
76
|
+
}) }) : null
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
TableLedgerCard.displayName = "TableLedgerCard";
|
|
83
|
+
|
|
84
|
+
export { TableLedgerCard, tableLedgerCardVariants };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TableTriggerBand — the way back to a live shared table from the venue's own
|
|
5
|
+
* pages: "You're at Table 18 · 3 people · 367 lei so far" (16-shared-table.html
|
|
6
|
+
* T0c), and the same band offering to start one when none is live (T0e).
|
|
7
|
+
*
|
|
8
|
+
* It is one target, not a card with a button in it. The frames draw a chevron
|
|
9
|
+
* under md and an "Open the table" button from md, but both mean "this band
|
|
10
|
+
* goes to the table", so the band is the link at both widths and `action`
|
|
11
|
+
* renders inside it as the wide screen's affordance — a span that looks like a
|
|
12
|
+
* button, `aria-hidden`, because the link already carries the name. A real
|
|
13
|
+
* button nested in a link is invalid HTML and gives a screen reader two
|
|
14
|
+
* controls where a reader sees one.
|
|
15
|
+
*
|
|
16
|
+
* `linkComponent` takes the app's router link (`next/link`); it falls back to
|
|
17
|
+
* `a`, so the design system imports no router.
|
|
18
|
+
*/
|
|
19
|
+
type TableTriggerBandProps = {
|
|
20
|
+
/** "You're at Table 18", "Start a table". */
|
|
21
|
+
title: React.ReactNode;
|
|
22
|
+
/** "3 people · 367 lei so far"; desktop draws the longer "Adrian, Bruno and you · opened 19:42". */
|
|
23
|
+
meta?: React.ReactNode;
|
|
24
|
+
/** The avatar stack — an `AvatarGroup`, or nothing when no table is live. */
|
|
25
|
+
people?: React.ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* The wide screen's call to action. Decorative: the band is the control, so
|
|
28
|
+
* this must NOT be a real `button` — a button inside an anchor is invalid
|
|
29
|
+
* HTML. Pass `<Button asChild><span>…</span></Button>`.
|
|
30
|
+
*/
|
|
31
|
+
action?: React.ReactNode;
|
|
32
|
+
href: string;
|
|
33
|
+
/** The app's link component. Defaults to `a`. */
|
|
34
|
+
linkComponent?: React.ElementType;
|
|
35
|
+
className?: string;
|
|
36
|
+
} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "title" | "action">;
|
|
37
|
+
declare const TableTriggerBand: React.ForwardRefExoticComponent<{
|
|
38
|
+
/** "You're at Table 18", "Start a table". */
|
|
39
|
+
title: React.ReactNode;
|
|
40
|
+
/** "3 people · 367 lei so far"; desktop draws the longer "Adrian, Bruno and you · opened 19:42". */
|
|
41
|
+
meta?: React.ReactNode;
|
|
42
|
+
/** The avatar stack — an `AvatarGroup`, or nothing when no table is live. */
|
|
43
|
+
people?: React.ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* The wide screen's call to action. Decorative: the band is the control, so
|
|
46
|
+
* this must NOT be a real `button` — a button inside an anchor is invalid
|
|
47
|
+
* HTML. Pass `<Button asChild><span>…</span></Button>`.
|
|
48
|
+
*/
|
|
49
|
+
action?: React.ReactNode;
|
|
50
|
+
href: string;
|
|
51
|
+
/** The app's link component. Defaults to `a`. */
|
|
52
|
+
linkComponent?: React.ElementType;
|
|
53
|
+
className?: string;
|
|
54
|
+
} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "title" | "href" | "action"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
55
|
+
|
|
56
|
+
export { TableTriggerBand, type TableTriggerBandProps };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cn } from '../chunk-FEK5XGZW.js';
|
|
2
|
+
import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ChevronRight } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var TableTriggerBand = React.forwardRef(
|
|
8
|
+
(_a, ref) => {
|
|
9
|
+
var _b = _a, { title, meta, people, action, href, linkComponent, className } = _b, props = __objRest(_b, ["title", "meta", "people", "action", "href", "linkComponent", "className"]);
|
|
10
|
+
const Link = linkComponent != null ? linkComponent : "a";
|
|
11
|
+
return /* @__PURE__ */ jsxs(
|
|
12
|
+
Link,
|
|
13
|
+
__spreadProps(__spreadValues({
|
|
14
|
+
ref,
|
|
15
|
+
href,
|
|
16
|
+
"data-slot": "table-trigger-band",
|
|
17
|
+
className: cn(
|
|
18
|
+
"flex items-center gap-3 rounded-2xl border border-primary bg-card px-3.5 py-3 transition-colors hover:bg-accent-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
19
|
+
className
|
|
20
|
+
)
|
|
21
|
+
}, props), {
|
|
22
|
+
children: [
|
|
23
|
+
people ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: people }) : null,
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
25
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-[15px] font-bold leading-tight", children: title }),
|
|
26
|
+
meta ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate text-[12.5px] text-muted-foreground", children: meta }) : null
|
|
27
|
+
] }),
|
|
28
|
+
action ? /* @__PURE__ */ jsx("span", { "data-slot": "table-trigger-action", "aria-hidden": true, className: "hidden shrink-0 md:block", children: action }) : null,
|
|
29
|
+
/* @__PURE__ */ jsx(
|
|
30
|
+
ChevronRight,
|
|
31
|
+
{
|
|
32
|
+
"aria-hidden": true,
|
|
33
|
+
className: cn("size-5 shrink-0 text-muted-foreground", action && "md:hidden")
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
TableTriggerBand.displayName = "TableTriggerBand";
|
|
42
|
+
|
|
43
|
+
export { TableTriggerBand };
|
package/dist/components/tag.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const tagVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare const Tag: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
|
|
10
|
-
variant?: "
|
|
10
|
+
variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
|
|
11
11
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
12
12
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
13
13
|
onRemove?: () => void;
|
|
@@ -22,8 +22,8 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
22
22
|
* Weights are 400 / 600 / 700. 500 is not in the system.
|
|
23
23
|
*/
|
|
24
24
|
declare const textVariants: (props?: ({
|
|
25
|
-
variant?: "body" | "
|
|
26
|
-
color?: "
|
|
25
|
+
variant?: "body" | "small" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
|
|
26
|
+
color?: "default" | "inherit" | "primary" | "destructive" | "muted" | "primary-foreground" | null | undefined;
|
|
27
27
|
weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
|
|
28
28
|
leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
|
|
29
29
|
tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
|
|
@@ -5,7 +5,7 @@ import * as TogglePrimitive from '@radix-ui/react-toggle';
|
|
|
5
5
|
import { VariantProps } from 'class-variance-authority';
|
|
6
6
|
|
|
7
7
|
declare const toggleVariants: (props?: ({
|
|
8
|
-
variant?: "
|
|
8
|
+
variant?: "default" | "tab" | "outline" | "chip" | "segmented" | null | undefined;
|
|
9
9
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
11
11
|
declare function Toggle({ className, variant, size, ...props }: React.ComponentProps<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>): react_jsx_runtime.JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { MenuItem } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
import { MenuItem } from '../chunk-XNBDACL7.js';
|
|
2
|
+
import '../chunk-6W25S5CF.js';
|
|
3
3
|
import { Separator } from '../chunk-NWZGSLPU.js';
|
|
4
4
|
import { Skeleton } from '../chunk-XBBEX4SF.js';
|
|
5
|
-
import '../chunk-
|
|
5
|
+
import '../chunk-NIAL4ZU2.js';
|
|
6
6
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
7
7
|
import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
|
|
8
8
|
import { MapPin, Star, MessageSquareQuote } from 'lucide-react';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Separator } from '../chunk-NWZGSLPU.js';
|
|
2
|
-
import { Card } from '../chunk-FVSKGCK3.js';
|
|
3
2
|
import { Skeleton } from '../chunk-XBBEX4SF.js';
|
|
3
|
+
import { Card } from '../chunk-FVSKGCK3.js';
|
|
4
4
|
import '../chunk-ZLMRVBD7.js';
|
|
5
5
|
import { cn } from '../chunk-FEK5XGZW.js';
|
|
6
6
|
import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bearmenu/ui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.34",
|
|
4
4
|
"packageManager": "pnpm@10.28.1",
|
|
5
5
|
"description": "BearMenu design system — shared UI tokens, primitives, and components",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
],
|
|
19
19
|
"exports": {
|
|
20
20
|
"./components/accordion": "./src/components/accordion.tsx",
|
|
21
|
+
"./components/action-bar": "./src/components/action-bar.tsx",
|
|
22
|
+
"./components/activity-row": "./src/components/activity-row.tsx",
|
|
21
23
|
"./components/alert": "./src/components/alert.tsx",
|
|
22
24
|
"./components/alert-dialog": "./src/components/alert-dialog.tsx",
|
|
23
25
|
"./components/aspect-ratio": "./src/components/aspect-ratio.tsx",
|
|
@@ -102,6 +104,7 @@
|
|
|
102
104
|
"./components/menu-index-list": "./src/components/menu-index-list.tsx",
|
|
103
105
|
"./components/menu-intent-hero": "./src/components/menu-intent-hero.tsx",
|
|
104
106
|
"./components/menu-item": "./src/components/menu-item.tsx",
|
|
107
|
+
"./components/menu-pick-row": "./src/components/menu-pick-row.tsx",
|
|
105
108
|
"./components/menu-kitchen-list": "./src/components/menu-kitchen-list.tsx",
|
|
106
109
|
"./components/menu-mocks": "./src/components/menu-mocks.ts",
|
|
107
110
|
"./components/menu-types": "./src/components/menu-types.ts",
|
|
@@ -128,8 +131,11 @@
|
|
|
128
131
|
"./components/poster-wall": "./src/components/poster-wall.tsx",
|
|
129
132
|
"./components/progress": "./src/components/progress.tsx",
|
|
130
133
|
"./components/qa-block": "./src/components/qa-block.tsx",
|
|
134
|
+
"./components/qr-panel": "./src/components/qr-panel.tsx",
|
|
131
135
|
"./components/quiet-stretch": "./src/components/quiet-stretch.tsx",
|
|
132
136
|
"./components/radio-group": "./src/components/radio-group.tsx",
|
|
137
|
+
"./components/reconcile-bar": "./src/components/reconcile-bar.tsx",
|
|
138
|
+
"./components/responsive-overlay": "./src/components/responsive-overlay.tsx",
|
|
133
139
|
"./components/rating": "./src/components/rating.tsx",
|
|
134
140
|
"./components/scroll-area": "./src/components/scroll-area.tsx",
|
|
135
141
|
"./components/scroll-fade": "./src/components/scroll-fade.tsx",
|
|
@@ -149,12 +155,15 @@
|
|
|
149
155
|
"./components/sonner": "./src/components/sonner.tsx",
|
|
150
156
|
"./components/sort-option-list": "./src/components/sort-option-list.tsx",
|
|
151
157
|
"./components/spinner": "./src/components/spinner.tsx",
|
|
158
|
+
"./components/split-share-row": "./src/components/split-share-row.tsx",
|
|
152
159
|
"./components/stat-banner": "./src/components/stat-banner.tsx",
|
|
153
160
|
"./components/stepper": "./src/components/stepper.tsx",
|
|
154
161
|
"./components/sticky-container": "./src/components/sticky-container.tsx",
|
|
155
162
|
"./components/story": "./src/components/story.tsx",
|
|
156
163
|
"./components/switch": "./src/components/switch.tsx",
|
|
157
164
|
"./components/table": "./src/components/table.tsx",
|
|
165
|
+
"./components/table-ledger-card": "./src/components/table-ledger-card.tsx",
|
|
166
|
+
"./components/table-trigger-band": "./src/components/table-trigger-band.tsx",
|
|
158
167
|
"./components/tabs": "./src/components/tabs.tsx",
|
|
159
168
|
"./components/tag": "./src/components/tag.tsx",
|
|
160
169
|
"./components/tag-group": "./src/components/tag-group.tsx",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { ActionBar } from "./action-bar";
|
|
3
|
+
import { Button } from "./button";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ActionBar> = {
|
|
6
|
+
title: "Shared table/ActionBar",
|
|
7
|
+
component: ActionBar,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
"The band that closes a screen or an overlay. With a note, the note takes the left and the actions sit right; without one, the actions divide the width and the primary takes the trailing edge. The bar owns the home-indicator inset.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof ActionBar>;
|
|
21
|
+
|
|
22
|
+
/** T2 — the table overview's pair, over the bottom nav. The one split bar. */
|
|
23
|
+
export const Split: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
layout: "split",
|
|
26
|
+
secondary: <Button variant="outline">Add item</Button>,
|
|
27
|
+
primary: <Button variant="cta">Organise</Button>,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** T6 desktop — two actions at their own width, on the trailing edge. */
|
|
32
|
+
export const TwoActions: Story = {
|
|
33
|
+
args: {
|
|
34
|
+
secondary: <Button variant="outline">Cancel</Button>,
|
|
35
|
+
primary: <Button variant="cta">Save split</Button>,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** T3 — the add-item overlay: the qualifier is read before the commit. */
|
|
40
|
+
export const WithNote: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
note: "Added items can be assigned afterwards.",
|
|
43
|
+
primary: <Button variant="cta">Add 1 item</Button>,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** T6 mobile — the split sheet commits and nothing else. */
|
|
48
|
+
export const PrimaryOnly: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
primary: <Button variant="cta">Save split</Button>,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** X10 — a split that does not balance cannot be saved. */
|
|
55
|
+
export const DisabledPrimary: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
note: "10 lei short of the item total.",
|
|
58
|
+
primary: (
|
|
59
|
+
<Button variant="cta" disabled className="bg-muted text-muted-foreground">
|
|
60
|
+
Save split
|
|
61
|
+
</Button>
|
|
62
|
+
),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const Sticky: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
sticky: true,
|
|
69
|
+
secondary: <Button variant="outline">Cancel</Button>,
|
|
70
|
+
primary: <Button variant="cta">Review</Button>,
|
|
71
|
+
},
|
|
72
|
+
render: (args) => (
|
|
73
|
+
<div className="h-64 overflow-y-auto rounded-xl border border-border">
|
|
74
|
+
<div className="h-80 bg-surface-2 p-4 text-sm text-muted-foreground">Scroll me.</div>
|
|
75
|
+
<ActionBar {...args} />
|
|
76
|
+
</div>
|
|
77
|
+
),
|
|
78
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../lib/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ActionBar — the band that closes a screen or an overlay: the note that
|
|
6
|
+
* qualifies the action on one side, the actions on the other.
|
|
7
|
+
*
|
|
8
|
+
* The shared-table board draws it three ways and they are one component
|
|
9
|
+
* (16-shared-table.html): the table overview's "Add item · Organise" pair
|
|
10
|
+
* over the bottom nav (T2), the add-item overlay's "Added items can be
|
|
11
|
+
* assigned afterwards." beside "Add 1 item" (T3), and the split sheet's lone
|
|
12
|
+
* "Save split" (T6). The booking flow draws the same band under its steps.
|
|
13
|
+
*
|
|
14
|
+
* Two rules the frames are consistent about:
|
|
15
|
+
* - The actions sit on the trailing edge at their own width, and `primary` is
|
|
16
|
+
* last. A `note` takes the left, so the qualifier is read before the commit.
|
|
17
|
+
* Only the table overview divides the bar between two equal buttons — that
|
|
18
|
+
* is `layout="split"`, not the default. (T5 and T6 draw a lone Save on the
|
|
19
|
+
* trailing edge; T6 and X10 draw Cancel + Save split right-aligned.)
|
|
20
|
+
* - The bar owns the home-indicator inset. `pb-[max(env(safe-area-inset-bottom),12px)]`
|
|
21
|
+
* is here and nowhere else, so no caller has to remember it.
|
|
22
|
+
*
|
|
23
|
+
* App-only offsets — bearmenu-fe's `--bottom-nav-offset`, `--page-gutter` —
|
|
24
|
+
* arrive through `className`. The design system does not know the app's
|
|
25
|
+
* chrome and must not guess at it.
|
|
26
|
+
*/
|
|
27
|
+
export type ActionBarProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
28
|
+
/** The commit. Trailing edge, always last in the DOM. */
|
|
29
|
+
primary: React.ReactNode;
|
|
30
|
+
/** The way out — Cancel, Keep organising. Sits before the primary. */
|
|
31
|
+
secondary?: React.ReactNode;
|
|
32
|
+
/** The line that qualifies the action. Takes the left when present. */
|
|
33
|
+
note?: React.ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* `end` (the default) keeps the actions at their own width on the trailing
|
|
36
|
+
* edge. `split` divides the bar between them — the table overview's
|
|
37
|
+
* "Add item · Organise" pair, and nothing else the board draws.
|
|
38
|
+
*/
|
|
39
|
+
layout?: "end" | "split";
|
|
40
|
+
/**
|
|
41
|
+
* Pins the bar to the bottom of its scroll container with the band's own
|
|
42
|
+
* ground and hairline. Off by default: inside an overlay the footer is
|
|
43
|
+
* already the last row of a flex column and does not need to stick.
|
|
44
|
+
*/
|
|
45
|
+
sticky?: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const ActionBar = React.forwardRef<HTMLDivElement, ActionBarProps>(
|
|
49
|
+
({ className, primary, secondary, note, layout = "end", sticky = false, ...props }, ref) => (
|
|
50
|
+
<div
|
|
51
|
+
ref={ref}
|
|
52
|
+
data-slot="action-bar"
|
|
53
|
+
className={cn(
|
|
54
|
+
"flex items-center gap-3 px-4 pt-3 pb-[max(env(safe-area-inset-bottom),12px)]",
|
|
55
|
+
sticky && "sticky bottom-0 z-10 border-t border-border bg-card",
|
|
56
|
+
className
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
>
|
|
60
|
+
{note ? (
|
|
61
|
+
<div data-slot="action-bar-note" className="min-w-0 flex-1 text-[12.5px] leading-normal text-muted-foreground">
|
|
62
|
+
{note}
|
|
63
|
+
</div>
|
|
64
|
+
) : null}
|
|
65
|
+
<div
|
|
66
|
+
data-slot="action-bar-actions"
|
|
67
|
+
className={cn(
|
|
68
|
+
"flex items-center gap-3",
|
|
69
|
+
layout === "split" ? "flex-1 [&>*]:flex-1" : "ml-auto shrink-0"
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{secondary}
|
|
73
|
+
{primary}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
ActionBar.displayName = "ActionBar";
|
|
79
|
+
|
|
80
|
+
export { ActionBar };
|