@david-richard/notify-ds 1.0.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.
- package/README.md +332 -0
- package/assets/icons/arrow-up.svg +3 -0
- package/assets/icons/bell-dot.svg +3 -0
- package/assets/icons/bell.svg +3 -0
- package/assets/icons/calendar.svg +3 -0
- package/assets/icons/chevron-left.svg +3 -0
- package/assets/icons/dashboard.svg +3 -0
- package/assets/icons/filter.svg +3 -0
- package/assets/icons/search.svg +3 -0
- package/assets/icons/store.svg +3 -0
- package/assets/icons/trending-down.svg +3 -0
- package/assets/icons/trending-up.svg +3 -0
- package/assets/logo-notify-lockup.svg +12 -0
- package/assets/logo-q-mark.svg +3 -0
- package/assets/logo-qu.svg +5 -0
- package/constraints.md +114 -0
- package/dist/index.d.mts +454 -0
- package/dist/index.d.ts +454 -0
- package/dist/index.js +1000 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +959 -0
- package/dist/index.mjs.map +1 -0
- package/fonts/ZillaSlab-Bold.ttf +0 -0
- package/fonts/ZillaSlab-BoldItalic.ttf +0 -0
- package/fonts/ZillaSlab-Italic.ttf +0 -0
- package/fonts/ZillaSlab-Light.ttf +0 -0
- package/fonts/ZillaSlab-LightItalic.ttf +0 -0
- package/fonts/ZillaSlab-Medium.ttf +0 -0
- package/fonts/ZillaSlab-MediumItalic.ttf +0 -0
- package/fonts/ZillaSlab-Regular.ttf +0 -0
- package/fonts/ZillaSlab-SemiBold.ttf +0 -0
- package/fonts/ZillaSlab-SemiBoldItalic.ttf +0 -0
- package/package.json +75 -0
- package/screen-anatomy.md +486 -0
- package/tailwind.config.js +180 -0
- package/tokens.css +519 -0
- package/tokens.json +285 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
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
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Button — shadcn-style primitive backed by the semantic tokens in tokens.css.
|
|
8
|
+
*
|
|
9
|
+
* Matrix:
|
|
10
|
+
* variant: primary | secondary | tertiary | link
|
|
11
|
+
* size: xsm | sm | md | lg
|
|
12
|
+
* state: active (default) | inactive | disabled — driven by `data-state` + `disabled`
|
|
13
|
+
*
|
|
14
|
+
* Use `<Button iconOnly />` (or `<IconButton />` below) to render the icon-only square form.
|
|
15
|
+
*/
|
|
16
|
+
declare const buttonVariants: (props?: ({
|
|
17
|
+
variant?: "primary" | "secondary" | "tertiary" | "link" | null | undefined;
|
|
18
|
+
size?: "xsm" | "sm" | "md" | "lg" | null | undefined;
|
|
19
|
+
iconOnly?: boolean | null | undefined;
|
|
20
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
21
|
+
type ButtonState = "active" | "inactive";
|
|
22
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
23
|
+
asChild?: boolean;
|
|
24
|
+
state?: ButtonState;
|
|
25
|
+
}
|
|
26
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
27
|
+
declare const IconButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "iconOnly"> & React.RefAttributes<HTMLButtonElement>>;
|
|
28
|
+
|
|
29
|
+
type InputState = "normal" | "active" | "filled" | "error" | "disabled" | "readonly";
|
|
30
|
+
type InputType = "default" | "password" | "search";
|
|
31
|
+
interface InputFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
32
|
+
/** Visual input type — controls icons and keyboard on mobile */
|
|
33
|
+
type?: InputType;
|
|
34
|
+
/** Controlled state override — set automatically on focus/blur if uncontrolled */
|
|
35
|
+
state?: InputState;
|
|
36
|
+
label?: string;
|
|
37
|
+
/** Whether to show the red required asterisk */
|
|
38
|
+
required?: boolean;
|
|
39
|
+
helperText?: string;
|
|
40
|
+
errorMessage?: string;
|
|
41
|
+
/** Slot for a custom right-side icon/action */
|
|
42
|
+
rightSlot?: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
declare const InputField: React.ForwardRefExoticComponent<InputFieldProps & React.RefAttributes<HTMLInputElement>>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Checkbox — Qu Notify form control.
|
|
48
|
+
*
|
|
49
|
+
* States: unchecked | checked | indeterminate | disabled
|
|
50
|
+
* - Unchecked: transparent fill, 1.5px teal (#339FB8) stroke, 4px radius
|
|
51
|
+
* - Checked: cyan (#40CCF2) fill, white checkmark, no stroke
|
|
52
|
+
* - Indeterminate: cyan fill, white dash, no stroke
|
|
53
|
+
* - Disabled: opacity 0.5 on full component
|
|
54
|
+
*
|
|
55
|
+
* Usage:
|
|
56
|
+
* <Checkbox label="Remember me" />
|
|
57
|
+
* <Checkbox checked label="Agreed to terms" />
|
|
58
|
+
* <Checkbox indeterminate label="Select all" />
|
|
59
|
+
* <Checkbox disabled label="Unavailable option" />
|
|
60
|
+
*/
|
|
61
|
+
interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
62
|
+
label?: string;
|
|
63
|
+
indeterminate?: boolean;
|
|
64
|
+
helperText?: string;
|
|
65
|
+
}
|
|
66
|
+
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Radio — Qu Notify form control.
|
|
70
|
+
*
|
|
71
|
+
* States: unselected | selected | disabled
|
|
72
|
+
* - Unselected: transparent fill, 1.5px teal (#339FB8) stroke, full radius
|
|
73
|
+
* - Selected: cyan (#40CCF2) fill, white center dot, no stroke
|
|
74
|
+
* - Disabled: opacity 0.5 on full component
|
|
75
|
+
*
|
|
76
|
+
* Usage (uncontrolled, group via same `name`):
|
|
77
|
+
* <Radio name="time" value="day" label="Day" />
|
|
78
|
+
* <Radio name="time" value="week" label="Week" defaultChecked />
|
|
79
|
+
* <Radio name="time" value="month" label="Month" />
|
|
80
|
+
*
|
|
81
|
+
* Usage (controlled):
|
|
82
|
+
* <Radio name="x" value="a" checked={val === "a"} onChange={() => setVal("a")} label="Option A" />
|
|
83
|
+
*/
|
|
84
|
+
interface RadioProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
85
|
+
label?: string;
|
|
86
|
+
helperText?: string;
|
|
87
|
+
}
|
|
88
|
+
declare const Radio: React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<HTMLInputElement>>;
|
|
89
|
+
/**
|
|
90
|
+
* RadioGroup — convenience wrapper for a labelled set of Radio options.
|
|
91
|
+
*
|
|
92
|
+
* Usage:
|
|
93
|
+
* <RadioGroup label="Time period" name="period" value={val} onChange={setVal}>
|
|
94
|
+
* <Radio value="day" label="Day" />
|
|
95
|
+
* <Radio value="week" label="Week" />
|
|
96
|
+
* <Radio value="month" label="Month" />
|
|
97
|
+
* </RadioGroup>
|
|
98
|
+
*/
|
|
99
|
+
interface RadioGroupProps {
|
|
100
|
+
label?: string;
|
|
101
|
+
name: string;
|
|
102
|
+
value?: string;
|
|
103
|
+
onChange?: (value: string) => void;
|
|
104
|
+
children: React.ReactNode;
|
|
105
|
+
className?: string;
|
|
106
|
+
orientation?: "horizontal" | "vertical";
|
|
107
|
+
}
|
|
108
|
+
declare function RadioGroup({ label, name, value, onChange, children, className, orientation, }: RadioGroupProps): react_jsx_runtime.JSX.Element;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Toggle — iOS-style switch. Qu Notify form control.
|
|
112
|
+
*
|
|
113
|
+
* States: off | on | disabled-off | disabled-on
|
|
114
|
+
* - Off: gray-100 (#DEDEDE) track, white knob positioned left
|
|
115
|
+
* - On: cyan (#40CCF2) track, white knob positioned right
|
|
116
|
+
* - Disabled: opacity 0.5 on full component
|
|
117
|
+
*
|
|
118
|
+
* Track: 44×24px, full-radius pill
|
|
119
|
+
* Knob: 20×20px white circle, 2px from edge, animates on toggle
|
|
120
|
+
*
|
|
121
|
+
* Usage:
|
|
122
|
+
* <Toggle label="Enable notifications" />
|
|
123
|
+
* <Toggle checked label="Push alerts" />
|
|
124
|
+
* <Toggle disabled label="Feature unavailable" />
|
|
125
|
+
*
|
|
126
|
+
* Controlled:
|
|
127
|
+
* <Toggle checked={enabled} onChange={(v) => setEnabled(v)} label="Face ID" />
|
|
128
|
+
*/
|
|
129
|
+
interface ToggleProps {
|
|
130
|
+
checked?: boolean;
|
|
131
|
+
defaultChecked?: boolean;
|
|
132
|
+
disabled?: boolean;
|
|
133
|
+
label?: string;
|
|
134
|
+
/** Label position relative to the toggle */
|
|
135
|
+
labelPosition?: "right" | "left";
|
|
136
|
+
helperText?: string;
|
|
137
|
+
onChange?: (checked: boolean) => void;
|
|
138
|
+
className?: string;
|
|
139
|
+
id?: string;
|
|
140
|
+
}
|
|
141
|
+
declare const Toggle: React.ForwardRefExoticComponent<ToggleProps & React.RefAttributes<HTMLButtonElement>>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Selector — pill-shaped dropdown trigger. Qu Notify filter/store-picker control.
|
|
145
|
+
*
|
|
146
|
+
* Variants:
|
|
147
|
+
* variant: primary | secondary
|
|
148
|
+
* state: active | inactive | disabled
|
|
149
|
+
*
|
|
150
|
+
* Primary Active: cyan (#40CCF2) fill, black text
|
|
151
|
+
* Primary Inactive: gray-100 fill, primary text
|
|
152
|
+
* Secondary Active: teal outline, teal text
|
|
153
|
+
* Secondary Inactive: gray-200 outline, secondary text
|
|
154
|
+
*
|
|
155
|
+
* The component is a styled button — wire up a Popover/DropdownMenu to it externally.
|
|
156
|
+
* The `open` prop controls the chevron rotation only.
|
|
157
|
+
*
|
|
158
|
+
* Usage:
|
|
159
|
+
* <Selector label="All Stores" />
|
|
160
|
+
* <Selector label="This Week" variant="secondary" state="active" />
|
|
161
|
+
* <Selector label="Location" open />
|
|
162
|
+
* <Selector label="Date Range" state="disabled" />
|
|
163
|
+
*/
|
|
164
|
+
declare const selectorVariants: (props?: ({
|
|
165
|
+
variant?: "primary" | "secondary" | null | undefined;
|
|
166
|
+
state?: "active" | "inactive" | "disabled" | null | undefined;
|
|
167
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
168
|
+
interface SelectorProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children">, VariantProps<typeof selectorVariants> {
|
|
169
|
+
label: string;
|
|
170
|
+
/** Controlled open state — rotates chevron 180° */
|
|
171
|
+
open?: boolean;
|
|
172
|
+
/** Icon to show before the label (optional) */
|
|
173
|
+
icon?: React.ReactNode;
|
|
174
|
+
}
|
|
175
|
+
declare const Selector: React.ForwardRefExoticComponent<SelectorProps & React.RefAttributes<HTMLButtonElement>>;
|
|
176
|
+
interface SelectorGroupProps {
|
|
177
|
+
children: React.ReactNode;
|
|
178
|
+
className?: string;
|
|
179
|
+
}
|
|
180
|
+
declare function SelectorGroup({ children, className }: SelectorGroupProps): react_jsx_runtime.JSX.Element;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* TabBar — Qu Notify segmented tab selector.
|
|
184
|
+
*
|
|
185
|
+
* Visual spec:
|
|
186
|
+
* Container: gray-100 (#DEDEDE) pill, 4px padding all sides, full-radius
|
|
187
|
+
* Selected tab: black fill, white text, full-radius pill
|
|
188
|
+
* Unselected tab: transparent, primary text
|
|
189
|
+
* Font: Inter Medium 14px
|
|
190
|
+
*
|
|
191
|
+
* Usage (uncontrolled):
|
|
192
|
+
* <TabBar tabs={["Sales", "Labor", "Store"]} defaultValue="Sales" />
|
|
193
|
+
*
|
|
194
|
+
* Usage (controlled):
|
|
195
|
+
* <TabBar
|
|
196
|
+
* tabs={["Sales", "Labor", "Store", "Product"]}
|
|
197
|
+
* value={activeTab}
|
|
198
|
+
* onValueChange={setActiveTab}
|
|
199
|
+
* />
|
|
200
|
+
*
|
|
201
|
+
* Usage with content panels:
|
|
202
|
+
* <TabBar tabs={tabs} value={active} onValueChange={setActive} />
|
|
203
|
+
* {active === "Sales" && <SalesPanel />}
|
|
204
|
+
*/
|
|
205
|
+
interface TabBarProps {
|
|
206
|
+
tabs: string[];
|
|
207
|
+
value?: string;
|
|
208
|
+
defaultValue?: string;
|
|
209
|
+
onValueChange?: (value: string) => void;
|
|
210
|
+
className?: string;
|
|
211
|
+
/** Make all tabs equal width (fills container) */
|
|
212
|
+
stretch?: boolean;
|
|
213
|
+
}
|
|
214
|
+
declare function TabBar({ tabs, value, defaultValue, onValueChange, className, stretch, }: TabBarProps): react_jsx_runtime.JSX.Element;
|
|
215
|
+
/**
|
|
216
|
+
* TabPanels — optional declarative panel companion for TabBar.
|
|
217
|
+
*
|
|
218
|
+
* Usage:
|
|
219
|
+
* <TabBar tabs={["Sales","Labor"]} value={tab} onValueChange={setTab} />
|
|
220
|
+
* <TabPanels value={tab}>
|
|
221
|
+
* <TabPanel value="Sales"><SalesContent /></TabPanel>
|
|
222
|
+
* <TabPanel value="Labor"><LaborContent /></TabPanel>
|
|
223
|
+
* </TabPanels>
|
|
224
|
+
*/
|
|
225
|
+
interface TabPanelsProps {
|
|
226
|
+
value: string;
|
|
227
|
+
children: React.ReactNode;
|
|
228
|
+
className?: string;
|
|
229
|
+
}
|
|
230
|
+
declare function TabPanels({ value, children, className }: TabPanelsProps): react_jsx_runtime.JSX.Element;
|
|
231
|
+
interface TabPanelProps {
|
|
232
|
+
value: string;
|
|
233
|
+
children: React.ReactNode;
|
|
234
|
+
className?: string;
|
|
235
|
+
}
|
|
236
|
+
declare function TabPanel({ children, className }: TabPanelProps): react_jsx_runtime.JSX.Element;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Switcher — Qu Notify segmented control (iOS-style).
|
|
240
|
+
*
|
|
241
|
+
* Visual spec:
|
|
242
|
+
* Container: gray-100 (#DEDEDE) bg, 8px corner radius, 3px padding
|
|
243
|
+
* Selected segment: black fill, white text, 6px corner radius
|
|
244
|
+
* Unselected segment: transparent, secondary text (gray)
|
|
245
|
+
* Font: Inter Medium 14px
|
|
246
|
+
*
|
|
247
|
+
* Differs from TabBar:
|
|
248
|
+
* - TabBar: full-radius pill, used for primary page-level navigation
|
|
249
|
+
* - Switcher: square-ish corners (8px), used for inline data filters
|
|
250
|
+
* (e.g. Day / Week / Month, Net / Gross, All / Open / Closed)
|
|
251
|
+
*
|
|
252
|
+
* Usage (uncontrolled):
|
|
253
|
+
* <Switcher segments={["Day", "Week", "Month"]} defaultValue="Week" />
|
|
254
|
+
*
|
|
255
|
+
* Usage (controlled):
|
|
256
|
+
* <Switcher
|
|
257
|
+
* segments={["Net", "Gross"]}
|
|
258
|
+
* value={metric}
|
|
259
|
+
* onValueChange={setMetric}
|
|
260
|
+
* />
|
|
261
|
+
*
|
|
262
|
+
* Usage with icon segments:
|
|
263
|
+
* <Switcher
|
|
264
|
+
* segments={[
|
|
265
|
+
* { value: "list", label: "List", icon: <ListIcon /> },
|
|
266
|
+
* { value: "grid", label: "Grid", icon: <GridIcon /> },
|
|
267
|
+
* ]}
|
|
268
|
+
* value={view}
|
|
269
|
+
* onValueChange={setView}
|
|
270
|
+
* />
|
|
271
|
+
*/
|
|
272
|
+
type Segment = string | {
|
|
273
|
+
value: string;
|
|
274
|
+
label: string;
|
|
275
|
+
icon?: React.ReactNode;
|
|
276
|
+
};
|
|
277
|
+
interface SwitcherProps {
|
|
278
|
+
segments: Segment[];
|
|
279
|
+
value?: string;
|
|
280
|
+
defaultValue?: string;
|
|
281
|
+
onValueChange?: (value: string) => void;
|
|
282
|
+
className?: string;
|
|
283
|
+
/** Stretch to fill container width */
|
|
284
|
+
stretch?: boolean;
|
|
285
|
+
}
|
|
286
|
+
declare function Switcher({ segments, value, defaultValue, onValueChange, className, stretch, }: SwitcherProps): react_jsx_runtime.JSX.Element;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* BottomNav — Qu Notify floating bottom navigation bar.
|
|
290
|
+
*
|
|
291
|
+
* Visual spec:
|
|
292
|
+
* Container: glass gradient pill (180deg, rgba(220,220,220,0.2) → rgba(118,118,118,0.2))
|
|
293
|
+
* box-shadow: 0 4px 4px rgba(0,0,0,0.14)
|
|
294
|
+
* border-radius: 60px
|
|
295
|
+
* max-width: 360px, height: 72px
|
|
296
|
+
* Selected item: black fill pill, white icon + label (Semi Bold)
|
|
297
|
+
* Unselected item: transparent, gray icon + label (Regular)
|
|
298
|
+
* Font: Inter — label 10px
|
|
299
|
+
* Icon: 20×20px
|
|
300
|
+
*
|
|
301
|
+
* Usage (controlled — you manage routing):
|
|
302
|
+
* const [active, setActive] = useState("dashboard")
|
|
303
|
+
*
|
|
304
|
+
* <BottomNav
|
|
305
|
+
* items={[
|
|
306
|
+
* { value: "dashboard", label: "Dashboard", icon: <DashboardIcon /> },
|
|
307
|
+
* { value: "inventory", label: "Inventory", icon: <BoxIcon /> },
|
|
308
|
+
* { value: "menu", label: "Menu", icon: <MenuIcon /> },
|
|
309
|
+
* ]}
|
|
310
|
+
* value={active}
|
|
311
|
+
* onValueChange={setActive}
|
|
312
|
+
* />
|
|
313
|
+
*
|
|
314
|
+
* Usage with React Router / Next.js:
|
|
315
|
+
* <BottomNav
|
|
316
|
+
* items={navItems}
|
|
317
|
+
* value={pathname}
|
|
318
|
+
* onValueChange={(v) => router.push(v)}
|
|
319
|
+
* />
|
|
320
|
+
*
|
|
321
|
+
* Positioning:
|
|
322
|
+
* Wrap in a <div className="fixed bottom-6 left-1/2 -translate-x-1/2 w-full max-w-sm px-4 z-50">
|
|
323
|
+
* for the standard bottom-floating placement used in the app.
|
|
324
|
+
*/
|
|
325
|
+
interface NavItem {
|
|
326
|
+
value: string;
|
|
327
|
+
label: string;
|
|
328
|
+
icon: React.ReactNode;
|
|
329
|
+
/** Notification indicator */
|
|
330
|
+
badge?: boolean | number;
|
|
331
|
+
}
|
|
332
|
+
interface BottomNavProps {
|
|
333
|
+
items: NavItem[];
|
|
334
|
+
value?: string;
|
|
335
|
+
defaultValue?: string;
|
|
336
|
+
onValueChange?: (value: string) => void;
|
|
337
|
+
className?: string;
|
|
338
|
+
}
|
|
339
|
+
declare function BottomNav({ items, value, defaultValue, onValueChange, className, }: BottomNavProps): react_jsx_runtime.JSX.Element;
|
|
340
|
+
declare function BottomNavContainer({ children }: {
|
|
341
|
+
children: React.ReactNode;
|
|
342
|
+
}): react_jsx_runtime.JSX.Element;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Badge — Qu Notify status/trend pill label.
|
|
346
|
+
*
|
|
347
|
+
* Variants:
|
|
348
|
+
* variant: default | success | error | warning | alert | info | neutral
|
|
349
|
+
* size: sm | md
|
|
350
|
+
*
|
|
351
|
+
* Usage:
|
|
352
|
+
* <Badge>Open</Badge>
|
|
353
|
+
* <Badge variant="success">+11.8%</Badge>
|
|
354
|
+
* <Badge variant="error">-5.6%</Badge>
|
|
355
|
+
* <Badge variant="warning">Delayed</Badge>
|
|
356
|
+
* <Badge icon={<TrendUpIcon />} variant="success">Net Sales</Badge>
|
|
357
|
+
*/
|
|
358
|
+
declare const badgeVariants: (props?: ({
|
|
359
|
+
variant?: "alert" | "error" | "default" | "success" | "warning" | "info" | "neutral" | "brand" | null | undefined;
|
|
360
|
+
size?: "sm" | "md" | null | undefined;
|
|
361
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
362
|
+
interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
|
|
363
|
+
icon?: React.ReactNode;
|
|
364
|
+
}
|
|
365
|
+
declare function Badge({ variant, size, icon, children, className, ...props }: BadgeProps): react_jsx_runtime.JSX.Element;
|
|
366
|
+
/**
|
|
367
|
+
* TrendBadge — convenience wrapper that picks variant from sign of the value.
|
|
368
|
+
*
|
|
369
|
+
* Usage:
|
|
370
|
+
* <TrendBadge value={11.8} /> → green "+11.8%"
|
|
371
|
+
* <TrendBadge value={-5.6} /> → red "−5.6%"
|
|
372
|
+
* <TrendBadge value={0} /> → neutral "0.0%"
|
|
373
|
+
*/
|
|
374
|
+
interface TrendBadgeProps extends Omit<BadgeProps, "variant" | "children"> {
|
|
375
|
+
value: number;
|
|
376
|
+
/** Number of decimal places (default: 1) */
|
|
377
|
+
decimals?: number;
|
|
378
|
+
/** Show arrow icon (default: true) */
|
|
379
|
+
showArrow?: boolean;
|
|
380
|
+
}
|
|
381
|
+
declare function TrendBadge({ value, decimals, showArrow, ...props }: TrendBadgeProps): react_jsx_runtime.JSX.Element;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* MetricTile — the core data display unit of the Qu Notify dashboard.
|
|
385
|
+
*
|
|
386
|
+
* Visual spec:
|
|
387
|
+
* Container: white card, 16px border-radius, shadow: 0 4px 4px rgba(0,0,0,0.06)
|
|
388
|
+
* Label: Inter Regular 12px, gray (#6B7280)
|
|
389
|
+
* Value: Inter SemiBold 24px, black (#000)
|
|
390
|
+
* Trend: TrendBadge (green/red/neutral)
|
|
391
|
+
* Sub-label: Inter Regular 12px, gray — secondary context (e.g. "vs last week")
|
|
392
|
+
*
|
|
393
|
+
* Variants:
|
|
394
|
+
* size: sm | md | lg
|
|
395
|
+
* loading: skeleton state
|
|
396
|
+
*
|
|
397
|
+
* Usage (minimal):
|
|
398
|
+
* <MetricTile label="Net Sales" value="$42,810" />
|
|
399
|
+
*
|
|
400
|
+
* Usage (with trend):
|
|
401
|
+
* <MetricTile label="Average Check" value="$18.42" trend={11.8} trendLabel="vs last week" />
|
|
402
|
+
*
|
|
403
|
+
* Usage (with icon and custom value color):
|
|
404
|
+
* <MetricTile
|
|
405
|
+
* label="Labor %"
|
|
406
|
+
* value="24.1%"
|
|
407
|
+
* trend={-2.3}
|
|
408
|
+
* icon={<UserIcon />}
|
|
409
|
+
* valueColor="var(--color-success,#16A34A)"
|
|
410
|
+
* />
|
|
411
|
+
*
|
|
412
|
+
* Usage (loading):
|
|
413
|
+
* <MetricTile label="Net Sales" value="..." loading />
|
|
414
|
+
*
|
|
415
|
+
* Usage (grid):
|
|
416
|
+
* <MetricTileGrid cols={2}>
|
|
417
|
+
* <MetricTile label="Net Sales" value="$42,810" trend={11.8} />
|
|
418
|
+
* <MetricTile label="Avg Check" value="$18.42" trend={-1.2} />
|
|
419
|
+
* <MetricTile label="Checks" value="2,324" />
|
|
420
|
+
* <MetricTile label="Speed of Svc" value="3m 12s" />
|
|
421
|
+
* </MetricTileGrid>
|
|
422
|
+
*/
|
|
423
|
+
interface MetricTileProps {
|
|
424
|
+
label: string;
|
|
425
|
+
value: string | number;
|
|
426
|
+
/** Percentage change. Positive = green, negative = red. */
|
|
427
|
+
trend?: number;
|
|
428
|
+
trendLabel?: string;
|
|
429
|
+
icon?: React.ReactNode;
|
|
430
|
+
/** Override the value text color (e.g. for KPI goal states) */
|
|
431
|
+
valueColor?: string;
|
|
432
|
+
size?: "sm" | "md" | "lg";
|
|
433
|
+
loading?: boolean;
|
|
434
|
+
/** Click handler — makes the tile interactive */
|
|
435
|
+
onClick?: () => void;
|
|
436
|
+
className?: string;
|
|
437
|
+
/** Render as a specific element */
|
|
438
|
+
as?: "div" | "article";
|
|
439
|
+
}
|
|
440
|
+
declare function MetricTile({ label, value, trend, trendLabel, icon, valueColor, size, loading, onClick, className, as: Tag, }: MetricTileProps): react_jsx_runtime.JSX.Element;
|
|
441
|
+
/**
|
|
442
|
+
* MetricTileGrid — responsive grid wrapper.
|
|
443
|
+
*
|
|
444
|
+
* Usage:
|
|
445
|
+
* <MetricTileGrid cols={2}> ... </MetricTileGrid>
|
|
446
|
+
*/
|
|
447
|
+
interface MetricTileGridProps {
|
|
448
|
+
cols?: 1 | 2 | 3 | 4;
|
|
449
|
+
children: React.ReactNode;
|
|
450
|
+
className?: string;
|
|
451
|
+
}
|
|
452
|
+
declare function MetricTileGrid({ cols, children, className }: MetricTileGridProps): react_jsx_runtime.JSX.Element;
|
|
453
|
+
|
|
454
|
+
export { Badge, type BadgeProps, BottomNav, BottomNavContainer, type BottomNavProps, Button, type ButtonProps, Checkbox, type CheckboxProps, IconButton, InputField, type InputFieldProps, MetricTile, MetricTileGrid, type MetricTileGridProps, type MetricTileProps, type NavItem, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Selector, SelectorGroup, type SelectorGroupProps, type SelectorProps, Switcher, type SwitcherProps, TabBar, type TabBarProps, TabPanel, type TabPanelProps, TabPanels, type TabPanelsProps, Toggle, type ToggleProps, TrendBadge, type TrendBadgeProps, buttonVariants };
|