@kodffe/ui 0.0.0-stage → 0.10.1
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/_virtual/_rolldown/runtime.js +11 -0
- package/dist/accordion/accordion.d.ts +44 -0
- package/dist/accordion/accordion.js +84 -0
- package/dist/accordion/accordion.js.map +1 -0
- package/dist/alert/alert.d.ts +17 -0
- package/dist/alert/alert.js +59 -0
- package/dist/alert/alert.js.map +1 -0
- package/dist/app-shell/app-footer.d.ts +29 -0
- package/dist/app-shell/app-footer.js +39 -0
- package/dist/app-shell/app-footer.js.map +1 -0
- package/dist/app-shell/app-shell-context.d.ts +10 -0
- package/dist/app-shell/app-shell-context.js +12 -0
- package/dist/app-shell/app-shell-context.js.map +1 -0
- package/dist/app-shell/app-shell.d.ts +42 -0
- package/dist/app-shell/app-shell.js +191 -0
- package/dist/app-shell/app-shell.js.map +1 -0
- package/dist/app-shell/floating-actions.d.ts +19 -0
- package/dist/app-shell/floating-actions.js +59 -0
- package/dist/app-shell/floating-actions.js.map +1 -0
- package/dist/app-shell/workspace-switcher.d.ts +25 -0
- package/dist/app-shell/workspace-switcher.js +82 -0
- package/dist/app-shell/workspace-switcher.js.map +1 -0
- package/dist/badge/badge.d.ts +19 -0
- package/dist/badge/badge.js +59 -0
- package/dist/badge/badge.js.map +1 -0
- package/dist/banner/banner.d.ts +22 -0
- package/dist/banner/banner.js +80 -0
- package/dist/banner/banner.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbs.d.ts +18 -0
- package/dist/breadcrumbs/breadcrumbs.js +45 -0
- package/dist/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/button/button.d.ts +38 -0
- package/dist/button/button.js +83 -0
- package/dist/button/button.js.map +1 -0
- package/dist/card/card.d.ts +159 -0
- package/dist/card/card.js +390 -0
- package/dist/card/card.js.map +1 -0
- package/dist/card/insight-card.d.ts +19 -0
- package/dist/card/insight-card.js +51 -0
- package/dist/card/insight-card.js.map +1 -0
- package/dist/card/integration-card.d.ts +19 -0
- package/dist/card/integration-card.js +70 -0
- package/dist/card/integration-card.js.map +1 -0
- package/dist/charts/charts.d.ts +75 -0
- package/dist/charts/charts.js +453 -0
- package/dist/charts/charts.js.map +1 -0
- package/dist/choice/choice.d.ts +39 -0
- package/dist/choice/choice.js +143 -0
- package/dist/choice/choice.js.map +1 -0
- package/dist/combobox/combobox.d.ts +46 -0
- package/dist/combobox/combobox.js +196 -0
- package/dist/combobox/combobox.js.map +1 -0
- package/dist/command-palette/command-palette.d.ts +35 -0
- package/dist/command-palette/command-palette.js +164 -0
- package/dist/command-palette/command-palette.js.map +1 -0
- package/dist/confirm-dialog/confirm-dialog.d.ts +37 -0
- package/dist/confirm-dialog/confirm-dialog.js +106 -0
- package/dist/confirm-dialog/confirm-dialog.js.map +1 -0
- package/dist/content/assistant.d.ts +86 -0
- package/dist/content/assistant.js +213 -0
- package/dist/content/assistant.js.map +1 -0
- package/dist/content/content.d.ts +45 -0
- package/dist/content/content.js +136 -0
- package/dist/content/content.js.map +1 -0
- package/dist/data-display/avatar-sizes.d.ts +8 -0
- package/dist/data-display/avatar-sizes.js +12 -0
- package/dist/data-display/avatar-sizes.js.map +1 -0
- package/dist/data-display/avatar.d.ts +21 -0
- package/dist/data-display/avatar.js +53 -0
- package/dist/data-display/avatar.js.map +1 -0
- package/dist/data-display/chip.d.ts +20 -0
- package/dist/data-display/chip.js +64 -0
- package/dist/data-display/chip.js.map +1 -0
- package/dist/data-display/code-block.d.ts +14 -0
- package/dist/data-display/code-block.js +50 -0
- package/dist/data-display/code-block.js.map +1 -0
- package/dist/data-display/data-display.d.ts +73 -0
- package/dist/data-display/data-display.js +227 -0
- package/dist/data-display/data-display.js.map +1 -0
- package/dist/data-display/insights.d.ts +120 -0
- package/dist/data-display/insights.js +220 -0
- package/dist/data-display/insights.js.map +1 -0
- package/dist/data-table/cells.d.ts +86 -0
- package/dist/data-table/cells.js +163 -0
- package/dist/data-table/cells.js.map +1 -0
- package/dist/data-table/data-table.d.ts +112 -0
- package/dist/data-table/data-table.js +558 -0
- package/dist/data-table/data-table.js.map +1 -0
- package/dist/date-picker/date-picker.d.ts +61 -0
- package/dist/date-picker/date-picker.js +309 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/drawer/drawer.d.ts +32 -0
- package/dist/drawer/drawer.js +72 -0
- package/dist/drawer/drawer.js.map +1 -0
- package/dist/empty-state/empty-state.d.ts +25 -0
- package/dist/empty-state/empty-state.js +78 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/error-state/error-state.d.ts +19 -0
- package/dist/error-state/error-state.js +56 -0
- package/dist/error-state/error-state.js.map +1 -0
- package/dist/event-calendar/calendar-logic.test.d.ts +1 -0
- package/dist/event-calendar/dates.d.ts +35 -0
- package/dist/event-calendar/dates.js +55 -0
- package/dist/event-calendar/dates.js.map +1 -0
- package/dist/event-calendar/event-calendar.d.ts +125 -0
- package/dist/event-calendar/event-calendar.js +795 -0
- package/dist/event-calendar/event-calendar.js.map +1 -0
- package/dist/event-calendar/event-details.d.ts +50 -0
- package/dist/event-calendar/event-details.js +124 -0
- package/dist/event-calendar/event-details.js.map +1 -0
- package/dist/event-calendar/layout.d.ts +48 -0
- package/dist/event-calendar/layout.js +55 -0
- package/dist/event-calendar/layout.js.map +1 -0
- package/dist/file-upload/file-upload.d.ts +70 -0
- package/dist/file-upload/file-upload.js +307 -0
- package/dist/file-upload/file-upload.js.map +1 -0
- package/dist/filters/filters.d.ts +48 -0
- package/dist/filters/filters.js +103 -0
- package/dist/filters/filters.js.map +1 -0
- package/dist/form-field/form-field.d.ts +39 -0
- package/dist/form-field/form-field.js +88 -0
- package/dist/form-field/form-field.js.map +1 -0
- package/dist/hover-card/hover-card.d.ts +15 -0
- package/dist/hover-card/hover-card.js +27 -0
- package/dist/hover-card/hover-card.js.map +1 -0
- package/dist/hover-card/person-hover-card.d.ts +26 -0
- package/dist/hover-card/person-hover-card.js +85 -0
- package/dist/hover-card/person-hover-card.js.map +1 -0
- package/dist/icon/icon-tile.d.ts +20 -0
- package/dist/icon/icon-tile.js +55 -0
- package/dist/icon/icon-tile.js.map +1 -0
- package/dist/icon/icon.d.ts +14 -0
- package/dist/icon/icon.js +28 -0
- package/dist/icon/icon.js.map +1 -0
- package/dist/icon/icons.generated.d.ts +358 -0
- package/dist/icon/icons.generated.js +362 -0
- package/dist/icon/icons.generated.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +88 -0
- package/dist/input/extra-inputs.d.ts +122 -0
- package/dist/input/extra-inputs.js +351 -0
- package/dist/input/extra-inputs.js.map +1 -0
- package/dist/input/field-styles.d.ts +5 -0
- package/dist/input/field-styles.js +14 -0
- package/dist/input/field-styles.js.map +1 -0
- package/dist/input/input.d.ts +50 -0
- package/dist/input/input.js +107 -0
- package/dist/input/input.js.map +1 -0
- package/dist/layout/layout.d.ts +41 -0
- package/dist/layout/layout.js +90 -0
- package/dist/layout/layout.js.map +1 -0
- package/dist/lib/control-styles.d.ts +9 -0
- package/dist/lib/control-styles.js +16 -0
- package/dist/lib/control-styles.js.map +1 -0
- package/dist/lib/cx.d.ts +2 -0
- package/dist/lib/cx.js +8 -0
- package/dist/lib/cx.js.map +1 -0
- package/dist/lib/glyphs.d.ts +13 -0
- package/dist/lib/glyphs.js +67 -0
- package/dist/lib/glyphs.js.map +1 -0
- package/dist/lib/segmented-styles.d.ts +8 -0
- package/dist/lib/segmented-styles.js +12 -0
- package/dist/lib/segmented-styles.js.map +1 -0
- package/dist/lib/select-on-arrow.d.ts +7 -0
- package/dist/lib/select-on-arrow.js +21 -0
- package/dist/lib/select-on-arrow.js.map +1 -0
- package/dist/lib/skip-link.d.ts +5 -0
- package/dist/lib/skip-link.js +13 -0
- package/dist/lib/skip-link.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +4 -0
- package/dist/lib/use-media-query.js +15 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lists/lists.d.ts +76 -0
- package/dist/lists/lists.js +133 -0
- package/dist/lists/lists.js.map +1 -0
- package/dist/locale-switch/locale-switch.d.ts +29 -0
- package/dist/locale-switch/locale-switch.js +62 -0
- package/dist/locale-switch/locale-switch.js.map +1 -0
- package/dist/logo/logo.d.ts +31 -0
- package/dist/logo/logo.js +157 -0
- package/dist/logo/logo.js.map +1 -0
- package/dist/logo/product-logo.d.ts +19 -0
- package/dist/logo/product-logo.js +46 -0
- package/dist/logo/product-logo.js.map +1 -0
- package/dist/marketing/marketing.d.ts +176 -0
- package/dist/marketing/marketing.js +451 -0
- package/dist/marketing/marketing.js.map +1 -0
- package/dist/marketing/newsletter-form.d.ts +21 -0
- package/dist/marketing/newsletter-form.js +100 -0
- package/dist/marketing/newsletter-form.js.map +1 -0
- package/dist/mascot/mascot.d.ts +28 -0
- package/dist/mascot/mascot.js +28 -0
- package/dist/mascot/mascot.js.map +1 -0
- package/dist/mascot/mascots.generated.d.ts +284 -0
- package/dist/mascot/mascots.generated.js +287 -0
- package/dist/mascot/mascots.generated.js.map +1 -0
- package/dist/master-detail/master-detail.d.ts +30 -0
- package/dist/master-detail/master-detail.js +71 -0
- package/dist/master-detail/master-detail.js.map +1 -0
- package/dist/menu/account-menu.d.ts +44 -0
- package/dist/menu/account-menu.js +78 -0
- package/dist/menu/account-menu.js.map +1 -0
- package/dist/menu/context-menu.d.ts +31 -0
- package/dist/menu/context-menu.js +111 -0
- package/dist/menu/context-menu.js.map +1 -0
- package/dist/menu/dropdown-menu.d.ts +49 -0
- package/dist/menu/dropdown-menu.js +152 -0
- package/dist/menu/dropdown-menu.js.map +1 -0
- package/dist/menu/menu-styles.d.ts +8 -0
- package/dist/menu/menu-styles.js +6 -0
- package/dist/menu/menu-styles.js.map +1 -0
- package/dist/menu/menubar.d.ts +31 -0
- package/dist/menu/menubar.js +125 -0
- package/dist/menu/menubar.js.map +1 -0
- package/dist/modal/modal.d.ts +34 -0
- package/dist/modal/modal.js +58 -0
- package/dist/modal/modal.js.map +1 -0
- package/dist/notification-center/notification-center.d.ts +51 -0
- package/dist/notification-center/notification-center.js +244 -0
- package/dist/notification-center/notification-center.js.map +1 -0
- package/dist/otp-input/otp-input.d.ts +23 -0
- package/dist/otp-input/otp-input.js +61 -0
- package/dist/otp-input/otp-input.js.map +1 -0
- package/dist/overlay/overlay.d.ts +53 -0
- package/dist/overlay/overlay.js +103 -0
- package/dist/overlay/overlay.js.map +1 -0
- package/dist/page-header/page-header.d.ts +55 -0
- package/dist/page-header/page-header.js +114 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/page-header/record-headers.d.ts +51 -0
- package/dist/page-header/record-headers.js +134 -0
- package/dist/page-header/record-headers.js.map +1 -0
- package/dist/page-header/section-header.d.ts +21 -0
- package/dist/page-header/section-header.js +44 -0
- package/dist/page-header/section-header.js.map +1 -0
- package/dist/page-navigation/page-navigation.d.ts +59 -0
- package/dist/page-navigation/page-navigation.js +136 -0
- package/dist/page-navigation/page-navigation.js.map +1 -0
- package/dist/pagination/pagination.d.ts +28 -0
- package/dist/pagination/pagination.js +102 -0
- package/dist/pagination/pagination.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +34 -0
- package/dist/phone-input/phone-input.js +171 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/popover.d.ts +23 -0
- package/dist/popover/popover.js +40 -0
- package/dist/popover/popover.js.map +1 -0
- package/dist/progress/progress.d.ts +21 -0
- package/dist/progress/progress.js +49 -0
- package/dist/progress/progress.js.map +1 -0
- package/dist/segmented-control/segmented-control.d.ts +32 -0
- package/dist/segmented-control/segmented-control.js +29 -0
- package/dist/segmented-control/segmented-control.js.map +1 -0
- package/dist/select/select.d.ts +48 -0
- package/dist/select/select.js +136 -0
- package/dist/select/select.js.map +1 -0
- package/dist/settings/permission-matrix.d.ts +29 -0
- package/dist/settings/permission-matrix.js +101 -0
- package/dist/settings/permission-matrix.js.map +1 -0
- package/dist/settings/settings-row.d.ts +32 -0
- package/dist/settings/settings-row.js +63 -0
- package/dist/settings/settings-row.js.map +1 -0
- package/dist/side-nav/side-nav.d.ts +36 -0
- package/dist/side-nav/side-nav.js +123 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/site-header/site-header.d.ts +32 -0
- package/dist/site-header/site-header.js +99 -0
- package/dist/site-header/site-header.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +16 -0
- package/dist/skeleton/skeleton.js +19 -0
- package/dist/skeleton/skeleton.js.map +1 -0
- package/dist/slider/slider.d.ts +15 -0
- package/dist/slider/slider.js +48 -0
- package/dist/slider/slider.js.map +1 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +42 -0
- package/dist/spinner/spinner.js.map +1 -0
- package/dist/stepper/step-dots.d.ts +16 -0
- package/dist/stepper/step-dots.js +26 -0
- package/dist/stepper/step-dots.js.map +1 -0
- package/dist/stepper/stepper.d.ts +26 -0
- package/dist/stepper/stepper.js +113 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/tabs/tabs.d.ts +31 -0
- package/dist/tabs/tabs.js +66 -0
- package/dist/tabs/tabs.js.map +1 -0
- package/dist/templates/app-templates.d.ts +126 -0
- package/dist/templates/app-templates.js +153 -0
- package/dist/templates/app-templates.js.map +1 -0
- package/dist/templates/site-templates.d.ts +49 -0
- package/dist/templates/site-templates.js +110 -0
- package/dist/templates/site-templates.js.map +1 -0
- package/dist/toast/toast-store.d.ts +54 -0
- package/dist/toast/toast-store.js +49 -0
- package/dist/toast/toast-store.js.map +1 -0
- package/dist/toast/toaster.d.ts +15 -0
- package/dist/toast/toaster.js +124 -0
- package/dist/toast/toaster.js.map +1 -0
- package/dist/tooltip/tooltip.d.ts +29 -0
- package/dist/tooltip/tooltip.js +54 -0
- package/dist/tooltip/tooltip.js.map +1 -0
- package/package.json +88 -3
- package/styles.css +521 -0
- package/README.md +0 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Icon as t } from "../icon/icon.js";
|
|
4
|
+
import { Glyph as n } from "../lib/glyphs.js";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
import { useEffect as a, useState as o } from "react";
|
|
7
|
+
//#region src/app-shell/floating-actions.tsx
|
|
8
|
+
function s({ primary: s, secondary: c = [], scrollTop: l = !0, labels: u = {}, className: d }) {
|
|
9
|
+
let [f, p] = o(!1);
|
|
10
|
+
a(() => {
|
|
11
|
+
if (!l) return;
|
|
12
|
+
let e = () => p(window.scrollY > 600);
|
|
13
|
+
return e(), window.addEventListener("scroll", e, { passive: !0 }), () => window.removeEventListener("scroll", e);
|
|
14
|
+
}, [l]);
|
|
15
|
+
let m = "grid size-11 cursor-pointer place-items-center rounded-full border border-border bg-surface text-fg shadow-raised hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus";
|
|
16
|
+
return /* @__PURE__ */ i("div", {
|
|
17
|
+
className: e("fixed right-[max(1rem,env(safe-area-inset-right))] bottom-[max(1rem,env(safe-area-inset-bottom))] z-40 flex flex-col items-end gap-2 font-sans", d),
|
|
18
|
+
children: [
|
|
19
|
+
l && f && /* @__PURE__ */ r("button", {
|
|
20
|
+
type: "button",
|
|
21
|
+
"aria-label": u.top ?? "Back to top",
|
|
22
|
+
title: u.top ?? "Back to top",
|
|
23
|
+
onClick: () => window.scrollTo({
|
|
24
|
+
top: 0,
|
|
25
|
+
behavior: "smooth"
|
|
26
|
+
}),
|
|
27
|
+
className: m,
|
|
28
|
+
children: /* @__PURE__ */ r(n, {
|
|
29
|
+
name: "arrow-up",
|
|
30
|
+
size: 18
|
|
31
|
+
})
|
|
32
|
+
}),
|
|
33
|
+
c.map((e) => /* @__PURE__ */ r("button", {
|
|
34
|
+
type: "button",
|
|
35
|
+
"aria-label": e.label,
|
|
36
|
+
title: e.label,
|
|
37
|
+
onClick: e.onClick,
|
|
38
|
+
className: m,
|
|
39
|
+
children: /* @__PURE__ */ r(t, {
|
|
40
|
+
name: e.icon,
|
|
41
|
+
size: 20
|
|
42
|
+
})
|
|
43
|
+
}, e.label)),
|
|
44
|
+
/* @__PURE__ */ i("button", {
|
|
45
|
+
type: "button",
|
|
46
|
+
onClick: s.onClick,
|
|
47
|
+
className: "inline-flex h-14 cursor-pointer items-center gap-2 rounded-full border-0 bg-primary px-5 font-semibold text-on-primary shadow-overlay hover:bg-primary-hover focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus",
|
|
48
|
+
children: [/* @__PURE__ */ r(t, {
|
|
49
|
+
name: s.icon,
|
|
50
|
+
size: 22
|
|
51
|
+
}), s.label]
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { s as FloatingActions };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=floating-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floating-actions.js","names":["FloatingActions","scrolled","setScrolled","useState","scrollTop","on","round","cx","className","labels","Glyph","secondary","a","Icon","primary"],"sources":["../../src/app-shell/floating-actions.tsx"],"sourcesContent":["'use client';\nimport { useEffect, useState } from 'react';\nimport { cx } from '../lib/cx';\nimport { Glyph } from '../lib/glyphs';\nimport { Icon, type IconName } from '../icon/icon';\n\n/* ---------------- FloatingActions ---------------- */\n\nexport interface FloatingAction {\n label: string;\n icon: IconName;\n onClick: () => void;\n}\n\n/**\n * The bottom-right floating button (the assistant) with optional secondary round buttons, plus \"Back to top\" after\n * scrolling. Respects the safe area on phones.\n */\nexport function FloatingActions({\n primary,\n secondary = [],\n scrollTop = true,\n labels = {},\n className,\n}: {\n primary: FloatingAction;\n secondary?: FloatingAction[];\n scrollTop?: boolean;\n labels?: { top?: string };\n className?: string;\n}) {\n const [scrolled, setScrolled] = useState(false);\n useEffect(() => {\n if (!scrollTop) return;\n const on = () => setScrolled(window.scrollY > 600);\n on();\n window.addEventListener('scroll', on, { passive: true });\n return () => window.removeEventListener('scroll', on);\n }, [scrollTop]);\n const round =\n 'grid size-11 cursor-pointer place-items-center rounded-full border border-border bg-surface text-fg shadow-raised hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus';\n return (\n <div\n className={cx(\n 'fixed right-[max(1rem,env(safe-area-inset-right))] bottom-[max(1rem,env(safe-area-inset-bottom))] z-40 flex flex-col items-end gap-2 font-sans',\n className,\n )}\n >\n {scrollTop && scrolled && (\n <button\n type=\"button\"\n aria-label={labels.top ?? 'Back to top'}\n title={labels.top ?? 'Back to top'}\n onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}\n className={round}\n >\n <Glyph name=\"arrow-up\" size={18} />\n </button>\n )}\n {secondary.map((a) => (\n <button key={a.label} type=\"button\" aria-label={a.label} title={a.label} onClick={a.onClick} className={round}>\n <Icon name={a.icon} size={20} />\n </button>\n ))}\n <button\n type=\"button\"\n onClick={primary.onClick}\n className=\"inline-flex h-14 cursor-pointer items-center gap-2 rounded-full border-0 bg-primary px-5 font-semibold text-on-primary shadow-overlay hover:bg-primary-hover focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus\"\n >\n <Icon name={primary.icon} size={22} />\n {primary.label}\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAkBA,SAAgBA,EAAgB,EAC9B,YACA,eAAY,CAAC,GACb,eAAY,IACZ,YAAS,CAAC,GACV,gBAOC;CACD,IAAM,CAACC,GAAUC,KAAeC,EAAS,EAAK;CAC9C,QAAgB;EACd,IAAI,CAACC,GAAW;EAChB,IAAMC,UAAWH,EAAY,OAAO,UAAU,GAAG;EAGjD,OAFAG,EAAG,GACH,OAAO,iBAAiB,UAAUA,GAAI,EAAE,SAAS,GAAK,CAAC,SAC1C,OAAO,oBAAoB,UAAUA,CAAE;CACtD,GAAG,CAACD,CAAS,CAAC;CACd,IAAME,IACJ;CACF,OACE,kBAAC,OAAD;EACE,WAAWC,EACT,kJACAC,CACF;EAJF,UAAA;GAMGJ,KAAaH,KACZ,kBAAC,UAAD;IACE,MAAK;IACL,cAAYQ,EAAO,OAAO;IAC1B,OAAOA,EAAO,OAAO;IACrB,eAAe,OAAO,SAAS;KAAE,KAAK;KAAG,UAAU;IAAS,CAAC;IAC7D,WAAWH;IAEX,UAAA,kBAACI,GAAD;KAAO,MAAK;KAAW,MAAM;IAAK,CAAA;GAC5B,CAAA;GAETC,EAAU,KAAK,MACd,kBAAC,UAAD;IAAsB,MAAK;IAAS,cAAYC,EAAE;IAAO,OAAOA,EAAE;IAAO,SAASA,EAAE;IAAS,WAAWN;IACtG,UAAA,kBAACO,GAAD;KAAM,MAAMD,EAAE;KAAM,MAAM;IAAK,CAAA;GACzB,GAFKA,EAAE,KAEP,CACT;GACD,kBAAC,UAAD;IACE,MAAK;IACL,SAASE,EAAQ;IACjB,WAAU;IAHZ,UAAA,CAKE,kBAACD,GAAD;KAAM,MAAMC,EAAQ;KAAM,MAAM;IAAK,CAAA,GACpCA,EAAQ,KACH;;EACL;;AAET"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface Workspace {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
/** Logo URL; otherwise the first letter on a colored tile. */
|
|
5
|
+
logoSrc?: string;
|
|
6
|
+
/** Tile color without a logo, e.g. `var(--kf-category-2)`. */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** A second line ("Owner", "12 members"). */
|
|
9
|
+
detail?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface WorkspaceSwitcherProps {
|
|
12
|
+
workspaces: Workspace[];
|
|
13
|
+
currentId: string;
|
|
14
|
+
onSelect?: (id: string) => void;
|
|
15
|
+
labels?: {
|
|
16
|
+
switch?: string;
|
|
17
|
+
workspaces?: string;
|
|
18
|
+
};
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The tenant at the top of the sidebar: logo and name in a card. With more than one workspace it opens a list
|
|
23
|
+
* to switch. In the collapsed sidebar rail only the tile shows.
|
|
24
|
+
*/
|
|
25
|
+
export declare function WorkspaceSwitcher({ workspaces, currentId, onSelect, labels, className }: WorkspaceSwitcherProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Glyph as t } from "../lib/glyphs.js";
|
|
4
|
+
import { DropdownMenu as n, DropdownMenuContent as r, DropdownMenuLabel as i, DropdownMenuRadioGroup as a, DropdownMenuRadioItem as o, DropdownMenuTrigger as s } from "../menu/dropdown-menu.js";
|
|
5
|
+
import { useAppShell as c } from "./app-shell-context.js";
|
|
6
|
+
import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
7
|
+
//#region src/app-shell/workspace-switcher.tsx
|
|
8
|
+
function f({ w: e }) {
|
|
9
|
+
return e.logoSrc ? /* @__PURE__ */ u("img", {
|
|
10
|
+
src: e.logoSrc,
|
|
11
|
+
alt: "",
|
|
12
|
+
className: "size-8 shrink-0 rounded-sm object-cover"
|
|
13
|
+
}) : /* @__PURE__ */ u("span", {
|
|
14
|
+
"aria-hidden": "true",
|
|
15
|
+
className: "grid size-8 shrink-0 place-items-center rounded-sm font-display text-sm font-bold text-white",
|
|
16
|
+
style: { background: e.color ?? "var(--kf-primary)" },
|
|
17
|
+
children: e.name.trim()[0]?.toUpperCase()
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function p({ workspaces: p, currentId: m, onSelect: h, labels: g = {}, className: _ }) {
|
|
21
|
+
let { collapsed: v } = c(), y = p.find((e) => e.id === m) ?? p[0];
|
|
22
|
+
if (!y) return null;
|
|
23
|
+
let b = p.length > 1, x = e("flex w-full min-w-0 items-center gap-2.5 rounded-md text-left font-sans text-fg", v ? "justify-center p-0" : "border border-border bg-surface p-2", _), S = /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(f, { w: y }), !v && /* @__PURE__ */ d("span", {
|
|
24
|
+
className: "grid min-w-0 flex-1",
|
|
25
|
+
children: [/* @__PURE__ */ u("span", {
|
|
26
|
+
className: "truncate text-sm font-semibold",
|
|
27
|
+
children: y.name
|
|
28
|
+
}), y.detail && /* @__PURE__ */ u("span", {
|
|
29
|
+
className: "truncate text-xs text-fg-muted",
|
|
30
|
+
children: y.detail
|
|
31
|
+
})]
|
|
32
|
+
})] });
|
|
33
|
+
return b ? /* @__PURE__ */ d(n, { children: [/* @__PURE__ */ u(s, {
|
|
34
|
+
asChild: !0,
|
|
35
|
+
children: /* @__PURE__ */ d("button", {
|
|
36
|
+
type: "button",
|
|
37
|
+
className: e(x, "cursor-pointer hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus"),
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ u("span", {
|
|
40
|
+
className: "sr-only",
|
|
41
|
+
children: g.switch ?? "Switch workspace"
|
|
42
|
+
}),
|
|
43
|
+
S,
|
|
44
|
+
!v && /* @__PURE__ */ u(t, {
|
|
45
|
+
name: "sort",
|
|
46
|
+
size: 16,
|
|
47
|
+
className: "shrink-0 text-fg-muted"
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
})
|
|
51
|
+
}), /* @__PURE__ */ d(r, {
|
|
52
|
+
align: "start",
|
|
53
|
+
className: "w-64",
|
|
54
|
+
children: [/* @__PURE__ */ u(i, { children: g.workspaces ?? "Workspaces" }), /* @__PURE__ */ u(a, {
|
|
55
|
+
value: y.id,
|
|
56
|
+
onValueChange: (e) => h?.(e),
|
|
57
|
+
children: p.map((e) => /* @__PURE__ */ u(o, {
|
|
58
|
+
value: e.id,
|
|
59
|
+
children: /* @__PURE__ */ d("span", {
|
|
60
|
+
className: "flex min-w-0 items-center gap-2.5",
|
|
61
|
+
children: [/* @__PURE__ */ u(f, { w: e }), /* @__PURE__ */ d("span", {
|
|
62
|
+
className: "grid min-w-0",
|
|
63
|
+
children: [/* @__PURE__ */ u("span", {
|
|
64
|
+
className: "truncate",
|
|
65
|
+
children: e.name
|
|
66
|
+
}), e.detail && /* @__PURE__ */ u("span", {
|
|
67
|
+
className: "truncate text-xs text-fg-muted",
|
|
68
|
+
children: e.detail
|
|
69
|
+
})]
|
|
70
|
+
})]
|
|
71
|
+
})
|
|
72
|
+
}, e.id))
|
|
73
|
+
})]
|
|
74
|
+
})] }) : /* @__PURE__ */ u("div", {
|
|
75
|
+
className: x,
|
|
76
|
+
children: S
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { p as WorkspaceSwitcher };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=workspace-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-switcher.js","names":["_Fragment","Tile","w","WorkspaceSwitcher","useAppShell","current","workspaces","currentId","many","card","cx","collapsed","className","body","Fragment","DropdownMenu","DropdownMenuTrigger","labels","Glyph","DropdownMenuContent","DropdownMenuLabel","DropdownMenuRadioGroup","onSelect","id","DropdownMenuRadioItem"],"sources":["../../src/app-shell/workspace-switcher.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from '../lib/cx';\nimport { Glyph } from '../lib/glyphs';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from '../menu/dropdown-menu';\nimport { useAppShell } from './app-shell-context';\n\nexport interface Workspace {\n id: string;\n name: string;\n /** Logo URL; otherwise the first letter on a colored tile. */\n logoSrc?: string;\n /** Tile color without a logo, e.g. `var(--kf-category-2)`. */\n color?: string;\n /** A second line (\"Owner\", \"12 members\"). */\n detail?: string;\n}\n\nexport interface WorkspaceSwitcherProps {\n workspaces: Workspace[];\n currentId: string;\n onSelect?: (id: string) => void;\n labels?: { switch?: string; workspaces?: string };\n className?: string;\n}\n\nfunction Tile({ w }: { w: Workspace }) {\n return w.logoSrc ? (\n <img src={w.logoSrc} alt=\"\" className=\"size-8 shrink-0 rounded-sm object-cover\" />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"grid size-8 shrink-0 place-items-center rounded-sm font-display text-sm font-bold text-white\"\n style={{ background: w.color ?? 'var(--kf-primary)' }}\n >\n {w.name.trim()[0]?.toUpperCase()}\n </span>\n );\n}\n\n/**\n * The tenant at the top of the sidebar: logo and name in a card. With more than one workspace it opens a list\n * to switch. In the collapsed sidebar rail only the tile shows.\n */\nexport function WorkspaceSwitcher({ workspaces, currentId, onSelect, labels = {}, className }: WorkspaceSwitcherProps) {\n const { collapsed } = useAppShell();\n const current = workspaces.find((w) => w.id === currentId) ?? workspaces[0];\n if (!current) return null;\n const many = workspaces.length > 1;\n const card = cx(\n 'flex w-full min-w-0 items-center gap-2.5 rounded-md text-left font-sans text-fg',\n // One padding and border per state: `cx` does not merge conflicting utilities.\n collapsed ? 'justify-center p-0' : 'border border-border bg-surface p-2',\n className,\n );\n const body = (\n <>\n <Tile w={current} />\n {!collapsed && (\n <span className=\"grid min-w-0 flex-1\">\n <span className=\"truncate text-sm font-semibold\">{current.name}</span>\n {current.detail && <span className=\"truncate text-xs text-fg-muted\">{current.detail}</span>}\n </span>\n )}\n </>\n );\n if (!many) return <div className={card}>{body}</div>;\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cx(\n card,\n 'cursor-pointer hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus',\n )}\n >\n {/* Visible text stays part of the name (\"Switch workspace SmartMuscle Admin\"). */}\n <span className=\"sr-only\">{labels.switch ?? 'Switch workspace'}</span>\n {body}\n {!collapsed && <Glyph name=\"sort\" size={16} className=\"shrink-0 text-fg-muted\" />}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-64\">\n <DropdownMenuLabel>{labels.workspaces ?? 'Workspaces'}</DropdownMenuLabel>\n <DropdownMenuRadioGroup value={current.id} onValueChange={(id) => onSelect?.(id)}>\n {workspaces.map((w) => (\n <DropdownMenuRadioItem key={w.id} value={w.id}>\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <Tile w={w} />\n <span className=\"grid min-w-0\">\n <span className=\"truncate\">{w.name}</span>\n {w.detail && <span className=\"truncate text-xs text-fg-muted\">{w.detail}</span>}\n </span>\n </span>\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":";;;;;;;AAiCA,SAASC,EAAK,EAAE,QAAuB;CACrC,OAAOC,EAAE,UACP,kBAAC,OAAD;EAAK,KAAKA,EAAE;EAAS,KAAI;EAAG,WAAU;CAA2C,CAAA,IAEjF,kBAAC,QAAD;EACE,eAAY;EACZ,WAAU;EACV,OAAO,EAAE,YAAYA,EAAE,SAAS,oBAAoB;EAEnD,UAAAA,EAAE,KAAK,KAAK,CAAC,CAAC,EAAE,EAAE,YAAY;CAC3B,CAAA;AAEV;AAMA,SAAgBC,EAAkB,EAAE,eAAY,cAAW,aAAU,YAAS,CAAC,GAAG,gBAAqC;CACrH,IAAM,EAAE,iBAAcC,EAAY,GAC5BC,IAAUC,EAAW,MAAM,MAAMJ,EAAE,OAAOK,CAAS,KAAKD,EAAW;CACzE,IAAI,CAACD,GAAS,OAAO;CACrB,IAAMG,IAAOF,EAAW,SAAS,GAC3BG,IAAOC,EACX,mFAEAC,IAAY,uBAAuB,uCACnCC,CACF,GACMC,IACJ,kBAAAb,GAAA,EAAA,UAAA,CACE,kBAACC,GAAD,EAAM,GAAGI,EAAU,CAAA,GAClB,CAACM,KACA,kBAAC,QAAD;EAAM,WAAU;EAAhB,UAAA,CACE,kBAAC,QAAD;GAAM,WAAU;GAAkC,UAAAN,EAAQ;EAAW,CAAA,GACpEA,EAAQ,UAAU,kBAAC,QAAD;GAAM,WAAU;GAAkC,UAAAA,EAAQ;EAAa,CAAA,CACtF;CAER,CAAA,CAAA,EAAA,CAAA;CAGJ,OADKG,IAEH,kBAACO,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD;EAAqB,SAAA;EACnB,UAAA,kBAAC,UAAD;GACE,MAAK;GACL,WAAWN,EACTD,GACA,0HACF;GALF,UAAA;IAQE,kBAAC,QAAD;KAAM,WAAU;KAAW,UAAAQ,EAAO,UAAU;IAAyB,CAAA;IACpEJ;IACA,CAACF,KAAa,kBAACO,GAAD;KAAO,MAAK;KAAO,MAAM;KAAI,WAAU;IAA0B,CAAA;GAC1E;;CACW,CAAA,GACrB,kBAACC,GAAD;EAAqB,OAAM;EAAQ,WAAU;EAA7C,UAAA,CACE,kBAACC,GAAD,EAAA,UAAoBH,EAAO,cAAc,aAAgC,CAAA,GACzE,kBAACI,GAAD;GAAwB,OAAOhB,EAAQ;GAAI,gBAAgB,MAAOiB,IAAWC,CAAE;GAC5E,UAAAjB,EAAW,KAAK,MACf,kBAACkB,GAAD;IAAkC,OAAOtB,EAAE;IACzC,UAAA,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,kBAACD,GAAD,EAAS,KAAI,CAAA,GACb,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OAAY,UAAAC,EAAE;MAAW,CAAA,GACxCA,EAAE,UAAU,kBAAC,QAAD;OAAM,WAAU;OAAkC,UAAAA,EAAE;MAAa,CAAA,CAC1E;KACF,CAAA,CAAA;;GACe,GARKA,EAAE,EAQP,CACxB;EACqB,CAAA,CACL;CACT,CAAA,CAAA,EAAA,CAAA,IAjCE,kBAAC,OAAD;EAAK,WAAWO;EAAO,UAAAI;CAAU,CAAA;AAmCrD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type IconName } from '../icon/icon';
|
|
3
|
+
export type BadgeVariant = 'live' | 'building' | 'client' | 'soon' | 'success' | 'warning' | 'danger' | 'info' | 'neutral';
|
|
4
|
+
export type BadgeAppearance = 'solid' | 'soft' | 'tag';
|
|
5
|
+
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
6
|
+
variant?: BadgeVariant;
|
|
7
|
+
/** Overrides the default icon of semantic variants. Pass `false` to hide it. */
|
|
8
|
+
icon?: IconName | false;
|
|
9
|
+
/**
|
|
10
|
+
* `solid` (default) for marketing and emphasis; `soft` for tables and dashboards; `tag` for neutral labels that
|
|
11
|
+
* are not a status (a team, a plan, "You", "Default"): outlined, the variant is ignored.
|
|
12
|
+
*/
|
|
13
|
+
appearance?: BadgeAppearance;
|
|
14
|
+
/** A small status dot instead of the icon (soft badges: Active, On trial, Failed…). */
|
|
15
|
+
dot?: boolean;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/** Short status label. Semantic variants always pair color with an icon (or a dot) and text. */
|
|
19
|
+
export declare function Badge({ variant, appearance, icon, dot, className, children, ...rest }: BadgeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Icon as t } from "../icon/icon.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/badge/badge.tsx
|
|
5
|
+
var i = {
|
|
6
|
+
live: { className: "bg-accent text-on-accent" },
|
|
7
|
+
building: { className: "bg-surface-muted text-link" },
|
|
8
|
+
client: { className: "bg-primary text-on-primary" },
|
|
9
|
+
soon: { className: "bg-surface-muted text-fg-muted" },
|
|
10
|
+
success: {
|
|
11
|
+
className: "bg-success-solid text-on-success-solid",
|
|
12
|
+
icon: "accept"
|
|
13
|
+
},
|
|
14
|
+
warning: {
|
|
15
|
+
className: "bg-warning-solid text-on-warning-solid",
|
|
16
|
+
icon: "warning"
|
|
17
|
+
},
|
|
18
|
+
danger: {
|
|
19
|
+
className: "bg-danger-solid text-on-danger-solid",
|
|
20
|
+
icon: "error"
|
|
21
|
+
},
|
|
22
|
+
info: {
|
|
23
|
+
className: "bg-primary text-on-primary",
|
|
24
|
+
icon: "info"
|
|
25
|
+
},
|
|
26
|
+
neutral: { className: "bg-surface-muted text-fg-muted" }
|
|
27
|
+
}, a = {
|
|
28
|
+
live: "bg-success-surface text-success-fg border-success-border",
|
|
29
|
+
building: "bg-surface-muted text-link border-transparent",
|
|
30
|
+
client: "bg-surface-muted text-link border-transparent",
|
|
31
|
+
soon: "bg-surface-muted text-fg-muted border-border",
|
|
32
|
+
success: "bg-success-surface text-success-fg border-success-border",
|
|
33
|
+
warning: "bg-warning-surface text-warning-fg border-warning-border",
|
|
34
|
+
danger: "bg-danger-surface text-danger-fg border-danger-border",
|
|
35
|
+
info: "bg-info-surface text-info-fg border-info-border",
|
|
36
|
+
neutral: "bg-surface-muted text-fg-muted border-border"
|
|
37
|
+
};
|
|
38
|
+
function o({ variant: o = "info", appearance: s = "solid", icon: c, dot: l, className: u, children: d, ...f }) {
|
|
39
|
+
let p = i[o], m = s === "tag", h = s === "soft" || m, g = l || c === !1 ? void 0 : c ?? (h ? void 0 : p.icon);
|
|
40
|
+
return /* @__PURE__ */ r("span", {
|
|
41
|
+
className: e("inline-flex items-center rounded-full font-sans leading-none", h ? "gap-1.5 border px-2.5 py-1 text-xs font-medium" : e("gap-1.5 py-1 text-[13px] font-semibold", g || l ? "pl-2 pr-3" : "px-3"), m ? "border-border bg-surface text-fg" : h ? a[o] : p.className, u),
|
|
42
|
+
...f,
|
|
43
|
+
children: [
|
|
44
|
+
l && /* @__PURE__ */ n("span", {
|
|
45
|
+
"aria-hidden": "true",
|
|
46
|
+
className: "size-1.5 shrink-0 rounded-full bg-current"
|
|
47
|
+
}),
|
|
48
|
+
g && /* @__PURE__ */ n(t, {
|
|
49
|
+
name: g,
|
|
50
|
+
size: h ? 14 : 18
|
|
51
|
+
}),
|
|
52
|
+
d
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { o as Badge };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","names":["VARIANTS","SOFT","Badge","rest","v","variant","tag","appearance","soft","iconName","dot","icon","cx","className","Icon","children"],"sources":["../../src/badge/badge.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Icon, type IconName } from '../icon/icon';\n\nexport type BadgeVariant =\n | 'live'\n | 'building'\n | 'client'\n | 'soon'\n | 'success'\n | 'warning'\n | 'danger'\n | 'info'\n | 'neutral';\nexport type BadgeAppearance = 'solid' | 'soft' | 'tag';\n\nconst VARIANTS: Record<BadgeVariant, { className: string; icon?: IconName }> = {\n live: { className: 'bg-accent text-on-accent' },\n building: { className: 'bg-surface-muted text-link' },\n client: { className: 'bg-primary text-on-primary' },\n soon: { className: 'bg-surface-muted text-fg-muted' },\n success: { className: 'bg-success-solid text-on-success-solid', icon: 'accept' },\n warning: { className: 'bg-warning-solid text-on-warning-solid', icon: 'warning' },\n danger: { className: 'bg-danger-solid text-on-danger-solid', icon: 'error' },\n info: { className: 'bg-primary text-on-primary', icon: 'info' },\n neutral: { className: 'bg-surface-muted text-fg-muted' },\n};\n\n/** Soft: tinted surface, colored text and a hairline border. For tables, lists and dashboards. */\nconst SOFT: Record<BadgeVariant, string> = {\n live: 'bg-success-surface text-success-fg border-success-border',\n building: 'bg-surface-muted text-link border-transparent',\n client: 'bg-surface-muted text-link border-transparent',\n soon: 'bg-surface-muted text-fg-muted border-border',\n success: 'bg-success-surface text-success-fg border-success-border',\n warning: 'bg-warning-surface text-warning-fg border-warning-border',\n danger: 'bg-danger-surface text-danger-fg border-danger-border',\n info: 'bg-info-surface text-info-fg border-info-border',\n neutral: 'bg-surface-muted text-fg-muted border-border',\n};\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: BadgeVariant;\n /** Overrides the default icon of semantic variants. Pass `false` to hide it. */\n icon?: IconName | false;\n /**\n * `solid` (default) for marketing and emphasis; `soft` for tables and dashboards; `tag` for neutral labels that\n * are not a status (a team, a plan, \"You\", \"Default\"): outlined, the variant is ignored.\n */\n appearance?: BadgeAppearance;\n /** A small status dot instead of the icon (soft badges: Active, On trial, Failed…). */\n dot?: boolean;\n children: ReactNode;\n}\n\n/** Short status label. Semantic variants always pair color with an icon (or a dot) and text. */\nexport function Badge({ variant = 'info', appearance = 'solid', icon, dot, className, children, ...rest }: BadgeProps) {\n const v = VARIANTS[variant];\n const tag = appearance === 'tag';\n const soft = appearance === 'soft' || tag;\n const iconName = dot || icon === false ? undefined : (icon ?? (soft ? undefined : v.icon));\n return (\n <span\n className={cx(\n 'inline-flex items-center rounded-full font-sans leading-none',\n soft\n ? 'gap-1.5 border px-2.5 py-1 text-xs font-medium'\n : cx('gap-1.5 py-1 text-[13px] font-semibold', iconName || dot ? 'pl-2 pr-3' : 'px-3'),\n tag ? 'border-border bg-surface text-fg' : soft ? SOFT[variant] : v.className,\n className,\n )}\n {...rest}\n >\n {dot && <span aria-hidden=\"true\" className=\"size-1.5 shrink-0 rounded-full bg-current\" />}\n {iconName && <Icon name={iconName} size={soft ? 14 : 18} />}\n {children}\n </span>\n );\n}\n"],"mappings":";;;;AAgBA,IAAMA,IAAyE;CAC7E,MAAM,EAAE,WAAW,2BAA2B;CAC9C,UAAU,EAAE,WAAW,6BAA6B;CACpD,QAAQ,EAAE,WAAW,6BAA6B;CAClD,MAAM,EAAE,WAAW,iCAAiC;CACpD,SAAS;EAAE,WAAW;EAA0C,MAAM;CAAS;CAC/E,SAAS;EAAE,WAAW;EAA0C,MAAM;CAAU;CAChF,QAAQ;EAAE,WAAW;EAAwC,MAAM;CAAQ;CAC3E,MAAM;EAAE,WAAW;EAA8B,MAAM;CAAO;CAC9D,SAAS,EAAE,WAAW,iCAAiC;AACzD,GAGMC,IAAqC;CACzC,MAAM;CACN,UAAU;CACV,QAAQ;CACR,MAAM;CACN,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,SAAS;AACX;AAiBA,SAAgBC,EAAM,EAAE,aAAU,QAAQ,gBAAa,SAAS,SAAM,QAAK,cAAW,aAAU,GAAGC,KAAoB;CACrH,IAAMC,IAAIJ,EAASK,IACbC,IAAMC,MAAe,OACrBC,IAAOD,MAAe,UAAUD,GAChCG,IAAWC,KAAOC,MAAS,KAAQ,KAAA,IAAaA,MAASH,IAAO,KAAA,IAAYJ,EAAE;CACpF,OACE,kBAAC,QAAD;EACE,WAAWQ,EACT,gEACAJ,IACI,mDACAI,EAAG,0CAA0CH,KAAYC,IAAM,cAAc,MAAM,GACvFJ,IAAM,qCAAqCE,IAAOP,EAAKI,KAAWD,EAAE,WACpES,CACF;EACA,GAAIV;EATN,UAAA;GAWGO,KAAO,kBAAC,QAAD;IAAM,eAAY;IAAO,WAAU;GAA6C,CAAA;GACvFD,KAAY,kBAACK,GAAD;IAAM,MAAML;IAAU,MAAMD,IAAO,KAAK;GAAK,CAAA;GACzDO;EACG;;AAEV"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type IconName } from '../icon/icon';
|
|
3
|
+
export type BannerVariant = 'brand' | 'info' | 'success' | 'warning' | 'danger';
|
|
4
|
+
export interface BannerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
5
|
+
variant?: BannerVariant;
|
|
6
|
+
/** Overrides the variant icon; `false` hides it. */
|
|
7
|
+
icon?: IconName | false;
|
|
8
|
+
/** Main message; keep it to one sentence. */
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/** Link or button, e.g. "Update payment method". */
|
|
11
|
+
action?: ReactNode;
|
|
12
|
+
/** Shows a dismiss button. Persist the dismissal yourself (e.g. per user, per announcement id). */
|
|
13
|
+
onDismiss?: () => void;
|
|
14
|
+
dismissLabel?: string;
|
|
15
|
+
/** Accessible name of the region, e.g. "Announcement". */
|
|
16
|
+
label?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Full-width, page-level message above the content or under the header: announcements, trials,
|
|
20
|
+
* billing or outage notices. One at a time. For messages about a section use `Alert`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Banner({ variant, icon, children, action, onDismiss, dismissLabel, label, className, ...rest }: BannerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Icon as t } from "../icon/icon.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/banner/banner.tsx
|
|
5
|
+
var i = {
|
|
6
|
+
brand: {
|
|
7
|
+
className: "bg-surface-inverse text-on-surface-inverse border-white/10",
|
|
8
|
+
icon: "ai",
|
|
9
|
+
iconClass: "text-accent"
|
|
10
|
+
},
|
|
11
|
+
info: {
|
|
12
|
+
className: "bg-info-surface text-info-fg border-info-border",
|
|
13
|
+
icon: "info",
|
|
14
|
+
iconClass: "text-info-icon"
|
|
15
|
+
},
|
|
16
|
+
success: {
|
|
17
|
+
className: "bg-success-surface text-success-fg border-success-border",
|
|
18
|
+
icon: "accept",
|
|
19
|
+
iconClass: "text-success-icon"
|
|
20
|
+
},
|
|
21
|
+
warning: {
|
|
22
|
+
className: "bg-warning-surface text-warning-fg border-warning-border",
|
|
23
|
+
icon: "warning",
|
|
24
|
+
iconClass: "text-warning-icon"
|
|
25
|
+
},
|
|
26
|
+
danger: {
|
|
27
|
+
className: "bg-danger-surface text-danger-fg border-danger-border",
|
|
28
|
+
icon: "error",
|
|
29
|
+
iconClass: "text-danger-icon"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function a({ variant: a = "info", icon: o, children: s, action: c, onDismiss: l, dismissLabel: u = "Dismiss", label: d = "Announcement", className: f, ...p }) {
|
|
33
|
+
let m = i[a], h = o === !1 ? void 0 : o ?? m.icon;
|
|
34
|
+
return /* @__PURE__ */ n("div", {
|
|
35
|
+
role: "region",
|
|
36
|
+
"aria-label": d,
|
|
37
|
+
className: e("w-full border-b font-sans", m.className, f),
|
|
38
|
+
...p,
|
|
39
|
+
children: /* @__PURE__ */ r("div", {
|
|
40
|
+
className: "mx-auto flex max-w-[75rem] flex-wrap items-center gap-x-4 gap-y-2 px-gutter py-2.5",
|
|
41
|
+
children: [/* @__PURE__ */ r("div", {
|
|
42
|
+
className: "flex min-w-0 flex-1 items-center gap-3",
|
|
43
|
+
children: [h && /* @__PURE__ */ n(t, {
|
|
44
|
+
name: h,
|
|
45
|
+
size: 22,
|
|
46
|
+
className: e("shrink-0", m.iconClass)
|
|
47
|
+
}), /* @__PURE__ */ n("p", {
|
|
48
|
+
className: "m-0 min-w-0 text-sm font-medium [&_a]:font-semibold [&_a]:text-current [&_a]:underline",
|
|
49
|
+
children: s
|
|
50
|
+
})]
|
|
51
|
+
}), (c || l) && /* @__PURE__ */ r("div", {
|
|
52
|
+
className: "flex shrink-0 items-center gap-2",
|
|
53
|
+
children: [c, l && /* @__PURE__ */ n("button", {
|
|
54
|
+
type: "button",
|
|
55
|
+
"aria-label": u,
|
|
56
|
+
onClick: l,
|
|
57
|
+
className: "-mr-2 grid size-8 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-current opacity-75 hover:bg-current/10 hover:opacity-100 focus-visible:outline-3 focus-visible:outline-offset-1 focus-visible:outline-focus",
|
|
58
|
+
children: /* @__PURE__ */ n("svg", {
|
|
59
|
+
viewBox: "0 0 24 24",
|
|
60
|
+
width: "16",
|
|
61
|
+
height: "16",
|
|
62
|
+
"aria-hidden": "true",
|
|
63
|
+
focusable: "false",
|
|
64
|
+
children: /* @__PURE__ */ n("path", {
|
|
65
|
+
d: "M6 6l12 12M18 6L6 18",
|
|
66
|
+
stroke: "currentColor",
|
|
67
|
+
strokeWidth: "2.25",
|
|
68
|
+
strokeLinecap: "round",
|
|
69
|
+
fill: "none"
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
})]
|
|
73
|
+
})]
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { a as Banner };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.js","names":["VARIANTS","Banner","rest","v","variant","iconName","icon","label","cx","className","Icon","action","onDismiss","dismissLabel"],"sources":["../../src/banner/banner.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Icon, type IconName } from '../icon/icon';\n\nexport type BannerVariant = 'brand' | 'info' | 'success' | 'warning' | 'danger';\n\nconst VARIANTS: Record<BannerVariant, { className: string; icon: IconName; iconClass: string }> = {\n brand: { className: 'bg-surface-inverse text-on-surface-inverse border-white/10', icon: 'ai', iconClass: 'text-accent' },\n info: { className: 'bg-info-surface text-info-fg border-info-border', icon: 'info', iconClass: 'text-info-icon' },\n success: { className: 'bg-success-surface text-success-fg border-success-border', icon: 'accept', iconClass: 'text-success-icon' },\n warning: { className: 'bg-warning-surface text-warning-fg border-warning-border', icon: 'warning', iconClass: 'text-warning-icon' },\n danger: { className: 'bg-danger-surface text-danger-fg border-danger-border', icon: 'error', iconClass: 'text-danger-icon' },\n};\n\nexport interface BannerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n variant?: BannerVariant;\n /** Overrides the variant icon; `false` hides it. */\n icon?: IconName | false;\n /** Main message; keep it to one sentence. */\n children: ReactNode;\n /** Link or button, e.g. \"Update payment method\". */\n action?: ReactNode;\n /** Shows a dismiss button. Persist the dismissal yourself (e.g. per user, per announcement id). */\n onDismiss?: () => void;\n dismissLabel?: string;\n /** Accessible name of the region, e.g. \"Announcement\". */\n label?: string;\n}\n\n/**\n * Full-width, page-level message above the content or under the header: announcements, trials,\n * billing or outage notices. One at a time. For messages about a section use `Alert`.\n */\nexport function Banner({\n variant = 'info',\n icon,\n children,\n action,\n onDismiss,\n dismissLabel = 'Dismiss',\n label = 'Announcement',\n className,\n ...rest\n}: BannerProps) {\n const v = VARIANTS[variant];\n const iconName = icon === false ? undefined : (icon ?? v.icon);\n return (\n <div\n role=\"region\"\n aria-label={label}\n className={cx('w-full border-b font-sans', v.className, className)}\n {...rest}\n >\n <div className=\"mx-auto flex max-w-[75rem] flex-wrap items-center gap-x-4 gap-y-2 px-gutter py-2.5\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n {iconName && <Icon name={iconName} size={22} className={cx('shrink-0', v.iconClass)} />}\n <p className=\"m-0 min-w-0 text-sm font-medium [&_a]:font-semibold [&_a]:text-current [&_a]:underline\">{children}</p>\n </div>\n {(action || onDismiss) && (\n <div className=\"flex shrink-0 items-center gap-2\">\n {action}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={dismissLabel}\n onClick={onDismiss}\n className=\"-mr-2 grid size-8 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-current opacity-75 hover:bg-current/10 hover:opacity-100 focus-visible:outline-3 focus-visible:outline-offset-1 focus-visible:outline-focus\"\n >\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M6 6l12 12M18 6L6 18\" stroke=\"currentColor\" strokeWidth=\"2.25\" strokeLinecap=\"round\" fill=\"none\" />\n </svg>\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAMA,IAAMA,IAA4F;CAChG,OAAO;EAAE,WAAW;EAA8D,MAAM;EAAM,WAAW;CAAc;CACvH,MAAM;EAAE,WAAW;EAAmD,MAAM;EAAQ,WAAW;CAAiB;CAChH,SAAS;EAAE,WAAW;EAA4D,MAAM;EAAU,WAAW;CAAoB;CACjI,SAAS;EAAE,WAAW;EAA4D,MAAM;EAAW,WAAW;CAAoB;CAClI,QAAQ;EAAE,WAAW;EAAyD,MAAM;EAAS,WAAW;CAAmB;AAC7H;AAqBA,SAAgBC,EAAO,EACrB,aAAU,QACV,SACA,aACA,WACA,cACA,kBAAe,WACf,WAAQ,gBACR,cACA,GAAGC,KACW;CACd,IAAMC,IAAIH,EAASI,IACbC,IAAWC,MAAS,KAAQ,KAAA,IAAaA,KAAQH,EAAE;CACzD,OACE,kBAAC,OAAD;EACE,MAAK;EACL,cAAYI;EACZ,WAAWC,EAAG,6BAA6BL,EAAE,WAAWM,CAAS;EACjE,GAAIP;EAEJ,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACGG,KAAY,kBAACK,GAAD;KAAM,MAAML;KAAU,MAAM;KAAI,WAAWG,EAAG,YAAYL,EAAE,SAAS;IAAI,CAAA,GACtF,kBAAC,KAAD;KAAG,WAAU;KAA0F;IAAY,CAAA,CAChH;GACH,CAAA,IAAAQ,KAAUC,MACV,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACGD,GACAC,KACC,kBAAC,UAAD;KACE,MAAK;KACL,cAAYC;KACZ,SAASD;KACT,WAAU;KAEV,UAAA,kBAAC,OAAD;MAAK,SAAQ;MAAY,OAAM;MAAK,QAAO;MAAK,eAAY;MAAO,WAAU;MAC3E,UAAA,kBAAC,QAAD;OAAM,GAAE;OAAuB,QAAO;OAAe,aAAY;OAAO,eAAc;OAAQ,MAAK;MAAQ,CAAA;KACxG,CAAA;IACC,CAAA,CAEP;GAEJ,CAAA,CAAA;;CACF,CAAA;AAET"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface BreadcrumbItem {
|
|
3
|
+
label: ReactNode;
|
|
4
|
+
/** Omit for the current page (last item). */
|
|
5
|
+
href?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BreadcrumbsProps extends HTMLAttributes<HTMLElement> {
|
|
8
|
+
items: BreadcrumbItem[];
|
|
9
|
+
/** Link component (e.g. Next.js `Link`). Receives `href`, `className`, `children`. */
|
|
10
|
+
linkAs?: ElementType;
|
|
11
|
+
/** Accessible name of the navigation landmark. */
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Shows where the page sits in the hierarchy. On mobile only the parent is shown as a
|
|
16
|
+
* "back" link; from `sm` the full trail.
|
|
17
|
+
*/
|
|
18
|
+
export declare function Breadcrumbs({ items, linkAs: Link, label, className, ...rest }: BreadcrumbsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Glyph as t } from "../lib/glyphs.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/breadcrumbs/breadcrumbs.tsx
|
|
5
|
+
function i({ items: i, linkAs: a = "a", label: o = "Breadcrumb", className: s, ...c }) {
|
|
6
|
+
let l = [...i].reverse().find((e, t) => t > 0 && e.href), u = "rounded-xs text-fg-muted no-underline hover:text-fg hover:underline focus-visible:outline-3 focus-visible:outline-focus";
|
|
7
|
+
return /* @__PURE__ */ r("nav", {
|
|
8
|
+
"aria-label": o,
|
|
9
|
+
className: e("font-sans text-sm", s),
|
|
10
|
+
...c,
|
|
11
|
+
children: [l && /* @__PURE__ */ r(a, {
|
|
12
|
+
href: l.href,
|
|
13
|
+
className: e(u, "inline-flex items-center gap-1 sm:hidden"),
|
|
14
|
+
children: [/* @__PURE__ */ n(t, {
|
|
15
|
+
name: "chevron-left",
|
|
16
|
+
size: 16
|
|
17
|
+
}), l.label]
|
|
18
|
+
}), /* @__PURE__ */ n("ol", {
|
|
19
|
+
className: "m-0 hidden list-none flex-wrap items-center gap-1.5 p-0 sm:flex",
|
|
20
|
+
children: i.map((o, s) => {
|
|
21
|
+
let c = s === i.length - 1;
|
|
22
|
+
return /* @__PURE__ */ r("li", {
|
|
23
|
+
className: "inline-flex items-center gap-1.5",
|
|
24
|
+
children: [c || !o.href ? /* @__PURE__ */ n("span", {
|
|
25
|
+
"aria-current": c ? "page" : void 0,
|
|
26
|
+
className: e(c ? "font-semibold text-fg" : "text-fg-muted"),
|
|
27
|
+
children: o.label
|
|
28
|
+
}) : /* @__PURE__ */ n(a, {
|
|
29
|
+
href: o.href,
|
|
30
|
+
className: u,
|
|
31
|
+
children: o.label
|
|
32
|
+
}), !c && /* @__PURE__ */ n(t, {
|
|
33
|
+
name: "chevron-right",
|
|
34
|
+
size: 14,
|
|
35
|
+
className: "text-fg-muted opacity-60"
|
|
36
|
+
})]
|
|
37
|
+
}, s);
|
|
38
|
+
})
|
|
39
|
+
})]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { i as Breadcrumbs };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=breadcrumbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breadcrumbs.js","names":["Breadcrumbs","Link","rest","parent","items","i","item","link","label","cx","className","Glyph","last"],"sources":["../../src/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Glyph } from '../lib/glyphs';\n\nexport interface BreadcrumbItem {\n label: ReactNode;\n /** Omit for the current page (last item). */\n href?: string;\n}\n\nexport interface BreadcrumbsProps extends HTMLAttributes<HTMLElement> {\n items: BreadcrumbItem[];\n /** Link component (e.g. Next.js `Link`). Receives `href`, `className`, `children`. */\n linkAs?: ElementType;\n /** Accessible name of the navigation landmark. */\n label?: string;\n}\n\n/**\n * Shows where the page sits in the hierarchy. On mobile only the parent is shown as a\n * \"back\" link; from `sm` the full trail.\n */\nexport function Breadcrumbs({ items, linkAs: Link = 'a', label = 'Breadcrumb', className, ...rest }: BreadcrumbsProps) {\n const parent = [...items].reverse().find((item, i) => i > 0 && item.href);\n const link =\n 'rounded-xs text-fg-muted no-underline hover:text-fg hover:underline focus-visible:outline-3 focus-visible:outline-focus';\n return (\n <nav aria-label={label} className={cx('font-sans text-sm', className)} {...rest}>\n {parent && (\n <Link href={parent.href} className={cx(link, 'inline-flex items-center gap-1 sm:hidden')}>\n <Glyph name=\"chevron-left\" size={16} />\n {parent.label}\n </Link>\n )}\n <ol className=\"m-0 hidden list-none flex-wrap items-center gap-1.5 p-0 sm:flex\">\n {items.map((item, i) => {\n const last = i === items.length - 1;\n return (\n <li key={i} className=\"inline-flex items-center gap-1.5\">\n {last || !item.href ? (\n <span\n aria-current={last ? 'page' : undefined}\n className={cx(last ? 'font-semibold text-fg' : 'text-fg-muted')}\n >\n {item.label}\n </span>\n ) : (\n <Link href={item.href} className={link}>\n {item.label}\n </Link>\n )}\n {!last && <Glyph name=\"chevron-right\" size={14} className=\"text-fg-muted opacity-60\" />}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"mappings":";;;;AAsBA,SAAgBA,EAAY,EAAE,UAAO,QAAQC,IAAO,KAAK,WAAQ,cAAc,cAAW,GAAGC,KAA0B;CACrH,IAAMC,IAAS,CAAC,GAAGC,CAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAM,MAAMC,IAAI,KAAKC,EAAK,IAAI,GAClEC,IACJ;CACF,OACE,kBAAC,OAAD;EAAK,cAAYC;EAAO,WAAWC,EAAG,qBAAqBC,CAAS;EAAG,GAAIR;EAA3E,UAAA,CACGC,KACC,kBAACF,GAAD;GAAM,MAAME,EAAO;GAAM,WAAWM,EAAGF,GAAM,0CAA0C;GAAvF,UAAA,CACE,kBAACI,GAAD;IAAO,MAAK;IAAe,MAAM;GAAK,CAAA,GACrCR,EAAO,KACJ;EAER,CAAA,GAAA,kBAAC,MAAD;GAAI,WAAU;GACX,UAAAC,EAAM,KAAK,GAAM,MAAM;IACtB,IAAMQ,IAAOP,MAAMD,EAAM,SAAS;IAClC,OACE,kBAAC,MAAD;KAAY,WAAU;KAAtB,UAAA,CACGQ,KAAQ,CAACN,EAAK,OACb,kBAAC,QAAD;MACE,gBAAcM,IAAO,SAAS,KAAA;MAC9B,WAAWH,EAAGG,IAAO,0BAA0B,eAAe;MAE7D,UAAAN,EAAK;KACF,CAAA,IAEN,kBAACL,GAAD;MAAM,MAAMK,EAAK;MAAM,WAAWC;MAC/B,UAAAD,EAAK;KACF,CAAA,GAEP,CAACM,KAAQ,kBAACD,GAAD;MAAO,MAAK;MAAgB,MAAM;MAAI,WAAU;KAA4B,CAAA,CACpF;IAdK,GAAAN,CAcL;GAER,CAAC;EACC,CAAA,CACD;;AAET"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type IconName } from '../icon/icon';
|
|
3
|
+
export type ButtonVariant = 'primary' | 'accent' | 'secondary' | 'ghost' | 'danger' | 'link' | 'inverse' | 'inverse-outline';
|
|
4
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
interface CommonProps {
|
|
6
|
+
variant?: ButtonVariant;
|
|
7
|
+
size?: ButtonSize;
|
|
8
|
+
/** Icon before the label (mascot icons render at 20px+ in `md`). */
|
|
9
|
+
iconStart?: IconName;
|
|
10
|
+
/** Icon after the label. */
|
|
11
|
+
iconEnd?: IconName;
|
|
12
|
+
/** Shows the mascot `loading` state, keeps the width and blocks clicks. */
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
fullWidth?: boolean;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
type AsButton = CommonProps & ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
18
|
+
href?: undefined;
|
|
19
|
+
};
|
|
20
|
+
type AsLink = CommonProps & AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
21
|
+
href: string;
|
|
22
|
+
};
|
|
23
|
+
export type ButtonProps = AsButton | AsLink;
|
|
24
|
+
/** Primary action control. Renders a link when `href` is set, a button otherwise. */
|
|
25
|
+
export declare function Button(props: ButtonProps): import("react").JSX.Element;
|
|
26
|
+
export type IconButtonVariant = 'ghost' | 'secondary' | 'primary' | 'danger' | 'inverse';
|
|
27
|
+
export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'aria-label'> {
|
|
28
|
+
icon: IconName;
|
|
29
|
+
/** Accessible name; also shown as the native tooltip unless `title` is set. Required: the button has no text. */
|
|
30
|
+
label: string;
|
|
31
|
+
variant?: IconButtonVariant;
|
|
32
|
+
/** `sm` 32 px (table rows), `md` 40 px (toolbars, top bar). Touch screens get at least 44 px. */
|
|
33
|
+
size?: 'sm' | 'md';
|
|
34
|
+
shape?: 'round' | 'square';
|
|
35
|
+
}
|
|
36
|
+
/** Icon-only action (edit, delete, notifications, close). Always has an accessible `label`. */
|
|
37
|
+
export declare function IconButton({ icon, label, variant, size, shape, type, title, className, ...rest }: IconButtonProps): import("react").JSX.Element;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { cx as e } from "../lib/cx.js";
|
|
2
|
+
import { Icon as t } from "../icon/icon.js";
|
|
3
|
+
import { Spinner as n } from "../spinner/spinner.js";
|
|
4
|
+
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
//#region src/button/button.tsx
|
|
6
|
+
var o = {
|
|
7
|
+
primary: "bg-primary text-on-primary hover:bg-primary-hover",
|
|
8
|
+
accent: "bg-accent text-on-accent hover:bg-accent-hover",
|
|
9
|
+
secondary: "bg-transparent text-link shadow-[inset_0_0_0_1.5px_currentColor] hover:bg-surface-muted",
|
|
10
|
+
danger: "bg-danger-solid text-on-danger-solid hover:bg-danger-solid-hover",
|
|
11
|
+
link: "bg-transparent text-link !px-0 underline-offset-4 hover:underline",
|
|
12
|
+
ghost: "bg-transparent text-fg hover:bg-surface-muted",
|
|
13
|
+
inverse: "bg-white text-primary hover:bg-white/90",
|
|
14
|
+
"inverse-outline": "bg-white/10 text-white shadow-[inset_0_0_0_1.5px_rgb(255_255_255/0.45)] hover:bg-white/20"
|
|
15
|
+
}, s = {
|
|
16
|
+
sm: {
|
|
17
|
+
button: "h-9 px-4 text-sm gap-2",
|
|
18
|
+
icon: 18
|
|
19
|
+
},
|
|
20
|
+
md: {
|
|
21
|
+
button: "h-11 px-5 text-[15px] gap-2",
|
|
22
|
+
icon: 20
|
|
23
|
+
},
|
|
24
|
+
lg: {
|
|
25
|
+
button: "h-14 px-7 text-[17px] gap-3",
|
|
26
|
+
icon: 22
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function c(c) {
|
|
30
|
+
let { variant: l = "primary", size: u = "md", iconStart: d, iconEnd: f, loading: p = !1, fullWidth: m = !1, className: h, children: g, ..._ } = c, v = s[u], y = e("inline-flex items-center justify-center whitespace-nowrap rounded-full font-sans font-semibold", "transition-[background-color,transform] duration-150 ease-standard hover:-translate-y-px active:translate-y-0", "focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus", "disabled:pointer-events-none disabled:opacity-45 aria-disabled:pointer-events-none aria-disabled:opacity-45", "motion-reduce:transition-none motion-reduce:hover:translate-y-0", o[l], v.button, m && "w-full", p && "pointer-events-none", h), b = /* @__PURE__ */ a(r, { children: [
|
|
31
|
+
p ? /* @__PURE__ */ i(n, { size: v.icon }) : d && /* @__PURE__ */ i(t, {
|
|
32
|
+
name: d,
|
|
33
|
+
size: v.icon
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ i("span", { children: g }),
|
|
36
|
+
!p && f && /* @__PURE__ */ i(t, {
|
|
37
|
+
name: f,
|
|
38
|
+
size: v.icon
|
|
39
|
+
})
|
|
40
|
+
] });
|
|
41
|
+
if (_.href !== void 0) {
|
|
42
|
+
let { href: e, ...t } = _;
|
|
43
|
+
return /* @__PURE__ */ i("a", {
|
|
44
|
+
href: e,
|
|
45
|
+
className: y,
|
|
46
|
+
"aria-busy": p || void 0,
|
|
47
|
+
...t,
|
|
48
|
+
children: b
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
let { type: x = "button", ...S } = _;
|
|
52
|
+
return /* @__PURE__ */ i("button", {
|
|
53
|
+
type: x,
|
|
54
|
+
className: y,
|
|
55
|
+
"aria-busy": p || void 0,
|
|
56
|
+
...S,
|
|
57
|
+
children: b
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
var l = {
|
|
61
|
+
ghost: "bg-transparent text-fg hover:bg-surface-muted",
|
|
62
|
+
secondary: "bg-surface text-fg shadow-[inset_0_0_0_1px_var(--kf-border)] hover:bg-surface-muted",
|
|
63
|
+
primary: "bg-primary text-on-primary hover:bg-primary-hover",
|
|
64
|
+
danger: "bg-transparent text-danger-fg hover:bg-danger-surface",
|
|
65
|
+
inverse: "bg-transparent text-white hover:bg-white/15"
|
|
66
|
+
};
|
|
67
|
+
function u({ icon: n, label: r, variant: a = "ghost", size: o = "md", shape: s = "round", type: c = "button", title: u, className: d, ...f }) {
|
|
68
|
+
return /* @__PURE__ */ i("button", {
|
|
69
|
+
type: c,
|
|
70
|
+
"aria-label": r,
|
|
71
|
+
title: u ?? r,
|
|
72
|
+
className: e("inline-grid shrink-0 cursor-pointer place-items-center border-0 transition-colors duration-150", "focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus", "disabled:pointer-events-none disabled:opacity-45 pointer-coarse:min-h-11 pointer-coarse:min-w-11", o === "sm" ? "size-8" : "size-10", s === "round" ? "rounded-full" : "rounded-sm", l[a], d),
|
|
73
|
+
...f,
|
|
74
|
+
children: /* @__PURE__ */ i(t, {
|
|
75
|
+
name: n,
|
|
76
|
+
size: o === "sm" ? 18 : 20
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { c as Button, u as IconButton };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","names":["_Fragment","VARIANTS","SIZES","Button","rest","props","s","size","classes","cx","variant","fullWidth","loading","className","content","Fragment","Spinner","iconStart","Icon","iconEnd","anchor","button","ICON_VARIANTS","IconButton","label","title","shape","icon"],"sources":["../../src/button/button.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Spinner } from '../spinner/spinner';\nimport { Icon, type IconName } from '../icon/icon';\n\nexport type ButtonVariant =\n | 'primary'\n | 'accent'\n | 'secondary'\n | 'ghost'\n | 'danger'\n | 'link'\n | 'inverse'\n | 'inverse-outline';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nconst VARIANTS: Record<ButtonVariant, string> = {\n primary: 'bg-primary text-on-primary hover:bg-primary-hover',\n accent: 'bg-accent text-on-accent hover:bg-accent-hover',\n secondary: 'bg-transparent text-link shadow-[inset_0_0_0_1.5px_currentColor] hover:bg-surface-muted',\n danger: 'bg-danger-solid text-on-danger-solid hover:bg-danger-solid-hover',\n link: 'bg-transparent text-link !px-0 underline-offset-4 hover:underline',\n /** Quiet actions in rows and toolbars (\"Edit\", \"Remove\", \"+ Add shift\"). */\n ghost: 'bg-transparent text-fg hover:bg-surface-muted',\n /** On a brand surface (page header band): white button with the brand color. */\n inverse: 'bg-white text-primary hover:bg-white/90',\n /** Secondary action on a brand surface. */\n 'inverse-outline': 'bg-white/10 text-white shadow-[inset_0_0_0_1.5px_rgb(255_255_255/0.45)] hover:bg-white/20',\n};\n\nconst SIZES: Record<ButtonSize, { button: string; icon: number }> = {\n sm: { button: 'h-9 px-4 text-sm gap-2', icon: 18 },\n md: { button: 'h-11 px-5 text-[15px] gap-2', icon: 20 },\n lg: { button: 'h-14 px-7 text-[17px] gap-3', icon: 22 },\n};\n\ninterface CommonProps {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Icon before the label (mascot icons render at 20px+ in `md`). */\n iconStart?: IconName;\n /** Icon after the label. */\n iconEnd?: IconName;\n /** Shows the mascot `loading` state, keeps the width and blocks clicks. */\n loading?: boolean;\n fullWidth?: boolean;\n children: ReactNode;\n}\n\ntype AsButton = CommonProps & ButtonHTMLAttributes<HTMLButtonElement> & { href?: undefined };\ntype AsLink = CommonProps & AnchorHTMLAttributes<HTMLAnchorElement> & { href: string };\nexport type ButtonProps = AsButton | AsLink;\n\n/** Primary action control. Renders a link when `href` is set, a button otherwise. */\nexport function Button(props: ButtonProps) {\n const { variant = 'primary', size = 'md', iconStart, iconEnd, loading = false, fullWidth = false, className, children, ...rest } = props;\n const s = SIZES[size];\n const classes = cx(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-full font-sans font-semibold',\n 'transition-[background-color,transform] duration-150 ease-standard hover:-translate-y-px active:translate-y-0',\n 'focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus',\n 'disabled:pointer-events-none disabled:opacity-45 aria-disabled:pointer-events-none aria-disabled:opacity-45',\n 'motion-reduce:transition-none motion-reduce:hover:translate-y-0',\n VARIANTS[variant],\n s.button,\n fullWidth && 'w-full',\n loading && 'pointer-events-none',\n className,\n );\n const content = (\n <>\n {loading ? <Spinner size={s.icon} /> : iconStart && <Icon name={iconStart} size={s.icon} />}\n <span>{children}</span>\n {!loading && iconEnd && <Icon name={iconEnd} size={s.icon} />}\n </>\n );\n\n if (rest.href !== undefined) {\n const { href, ...anchor } = rest as AnchorHTMLAttributes<HTMLAnchorElement>;\n return (\n <a href={href} className={classes} aria-busy={loading || undefined} {...anchor}>\n {content}\n </a>\n );\n }\n const { type = 'button', ...button } = rest as ButtonHTMLAttributes<HTMLButtonElement>;\n return (\n <button type={type} className={classes} aria-busy={loading || undefined} {...button}>\n {content}\n </button>\n );\n}\n\nexport type IconButtonVariant = 'ghost' | 'secondary' | 'primary' | 'danger' | 'inverse';\n\nexport interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'aria-label'> {\n icon: IconName;\n /** Accessible name; also shown as the native tooltip unless `title` is set. Required: the button has no text. */\n label: string;\n variant?: IconButtonVariant;\n /** `sm` 32 px (table rows), `md` 40 px (toolbars, top bar). Touch screens get at least 44 px. */\n size?: 'sm' | 'md';\n shape?: 'round' | 'square';\n}\n\nconst ICON_VARIANTS: Record<IconButtonVariant, string> = {\n ghost: 'bg-transparent text-fg hover:bg-surface-muted',\n secondary: 'bg-surface text-fg shadow-[inset_0_0_0_1px_var(--kf-border)] hover:bg-surface-muted',\n primary: 'bg-primary text-on-primary hover:bg-primary-hover',\n danger: 'bg-transparent text-danger-fg hover:bg-danger-surface',\n inverse: 'bg-transparent text-white hover:bg-white/15',\n};\n\n/** Icon-only action (edit, delete, notifications, close). Always has an accessible `label`. */\nexport function IconButton({\n icon,\n label,\n variant = 'ghost',\n size = 'md',\n shape = 'round',\n type = 'button',\n title,\n className,\n ...rest\n}: IconButtonProps) {\n return (\n <button\n type={type}\n aria-label={label}\n title={title ?? label}\n className={cx(\n 'inline-grid shrink-0 cursor-pointer place-items-center border-0 transition-colors duration-150',\n 'focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus',\n 'disabled:pointer-events-none disabled:opacity-45 pointer-coarse:min-h-11 pointer-coarse:min-w-11',\n size === 'sm' ? 'size-8' : 'size-10',\n shape === 'round' ? 'rounded-full' : 'rounded-sm',\n ICON_VARIANTS[variant],\n className,\n )}\n {...rest}\n >\n <Icon name={icon} size={size === 'sm' ? 18 : 20} />\n </button>\n );\n}\n"],"mappings":";;;;;AAgBA,IAAMC,IAA0C;CAC9C,SAAS;CACT,QAAQ;CACR,WAAW;CACX,QAAQ;CACR,MAAM;CAEN,OAAO;CAEP,SAAS;CAET,mBAAmB;AACrB,GAEMC,IAA8D;CAClE,IAAI;EAAE,QAAQ;EAA0B,MAAM;CAAG;CACjD,IAAI;EAAE,QAAQ;EAA+B,MAAM;CAAG;CACtD,IAAI;EAAE,QAAQ;EAA+B,MAAM;CAAG;AACxD;AAoBA,SAAgBC,EAAO,GAAoB;CACzC,IAAM,EAAE,aAAU,WAAW,UAAO,MAAM,cAAW,YAAS,aAAU,IAAO,eAAY,IAAO,cAAW,aAAU,GAAGC,MAASC,GAC7HC,IAAIJ,EAAMK,IACVC,IAAUC,EACd,kGACA,iHACA,sFACA,+GACA,mEACAR,EAASS,IACTJ,EAAE,QACFK,KAAa,UACbC,KAAW,uBACXC,CACF,GACMC,IACJ,kBAAAd,GAAA,EAAA,UAAA;EACGY,IAAU,kBAACI,GAAD,EAAS,MAAMV,EAAE,KAAO,CAAA,IAAIW,KAAa,kBAACC,GAAD;GAAM,MAAMD;GAAW,MAAMX,EAAE;EAAO,CAAA;EAC1F,kBAAC,QAAD,EAAO,YAAe,CAAA;EACrB,CAACM,KAAWO,KAAW,kBAACD,GAAD;GAAM,MAAMC;GAAS,MAAMb,EAAE;EAAO,CAAA;CAC5D,EAAA,CAAA;CAGJ,IAAIF,EAAK,SAAS,KAAA,GAAW;EAC3B,IAAM,EAAE,SAAM,GAAGgB,MAAWhB;EAC5B,OACE,kBAAC,KAAD;GAAS;GAAM,WAAWI;GAAS,aAAWI,KAAW,KAAA;GAAW,GAAIQ;GACrE,UAAAN;EACA,CAAA;CAEP;CACA,IAAM,EAAE,UAAO,UAAU,GAAGO,MAAWjB;CACvC,OACE,kBAAC,UAAD;EAAc;EAAM,WAAWI;EAAS,aAAWI,KAAW,KAAA;EAAW,GAAIS;EAC1E,UAAAP;CACK,CAAA;AAEZ;AAcA,IAAMQ,IAAmD;CACvD,OAAO;CACP,WAAW;CACX,SAAS;CACT,QAAQ;CACR,SAAS;AACX;AAGA,SAAgBC,EAAW,EACzB,SACA,UACA,aAAU,SACV,UAAO,MACP,WAAQ,SACR,UAAO,UACP,UACA,cACA,GAAGnB,KACe;CAClB,OACE,kBAAC,UAAD;EACQ;EACN,cAAYoB;EACZ,OAAOC,KAASD;EAChB,WAAWf,EACT,kGACA,sFACA,oGACAF,MAAS,OAAO,WAAW,WAC3BmB,MAAU,UAAU,iBAAiB,cACrCJ,EAAcZ,IACdG,CACF;EACA,GAAIT;EAEJ,UAAA,kBAACc,GAAD;GAAM,MAAMS;GAAM,MAAMpB,MAAS,OAAO,KAAK;EAAK,CAAA;CAC5C,CAAA;AAEZ"}
|