@ngrok/mantle 0.70.0 → 0.70.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/accordion.d.ts +2 -2
- package/dist/accordion.js +1 -1
- package/dist/accordion.js.map +1 -1
- package/dist/alert-dialog.d.ts +3 -3
- package/dist/alert-dialog.js +1 -1
- package/dist/alert-dialog.js.map +1 -1
- package/dist/alert.d.ts +1 -1
- package/dist/alert.js +1 -1
- package/dist/alert.js.map +1 -1
- package/dist/anchor-2stEauOz.js +2 -0
- package/dist/anchor-2stEauOz.js.map +1 -0
- package/dist/anchor.js +1 -1
- package/dist/badge.js +1 -1
- package/dist/badge.js.map +1 -1
- package/dist/{button-BKykcpgJ.js → button-GokecthL.js} +2 -2
- package/dist/{button-BKykcpgJ.js.map → button-GokecthL.js.map} +1 -1
- package/dist/button-POMJ-20y.js +2 -0
- package/dist/button-POMJ-20y.js.map +1 -0
- package/dist/button.d.ts +1 -1
- package/dist/button.js +1 -1
- package/dist/calendar.js +1 -1
- package/dist/calendar.js.map +1 -1
- package/dist/card.js +1 -1
- package/dist/card.js.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/code-block.d.ts +1 -1
- package/dist/code-block.js +1 -1
- package/dist/code-block.js.map +1 -1
- package/dist/code.d.ts +2 -2
- package/dist/code.js +1 -1
- package/dist/code.js.map +1 -1
- package/dist/combobox.js +1 -1
- package/dist/combobox.js.map +1 -1
- package/dist/command.d.ts +2 -2
- package/dist/command.js +1 -1
- package/dist/command.js.map +1 -1
- package/dist/data-table.d.ts +1 -1
- package/dist/data-table.js +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/description-list.js +1 -1
- package/dist/description-list.js.map +1 -1
- package/dist/dialog-MiS_Q-ge.js +2 -0
- package/dist/dialog-MiS_Q-ge.js.map +1 -0
- package/dist/dialog.d.ts +2 -2
- package/dist/dialog.js +1 -1
- package/dist/{dropdown-menu-BwQDoun1.d.ts → dropdown-menu-C9f9Y8Ov.d.ts} +2 -2
- package/dist/dropdown-menu-Ff97BIJe.js +2 -0
- package/dist/dropdown-menu-Ff97BIJe.js.map +1 -0
- package/dist/dropdown-menu.d.ts +1 -1
- package/dist/dropdown-menu.js +1 -1
- package/dist/empty.d.ts +5 -3
- package/dist/empty.js +1 -1
- package/dist/empty.js.map +1 -1
- package/dist/flag.js +1 -1
- package/dist/flag.js.map +1 -1
- package/dist/hover-card.d.ts +9 -1
- package/dist/hover-card.js +1 -1
- package/dist/hover-card.js.map +1 -1
- package/dist/{icon-C7Dje_lR.d.ts → icon-C0YAAaLZ.d.ts} +2 -2
- package/dist/icon-bWc5yC3-.js +2 -0
- package/dist/{icon-BMH0fD_b.js.map → icon-bWc5yC3-.js.map} +1 -1
- package/dist/{icon-button-CxxVPiKp.js → icon-button-ZKN0sRIJ.js} +2 -2
- package/dist/{icon-button-CxxVPiKp.js.map → icon-button-ZKN0sRIJ.js.map} +1 -1
- package/dist/icon.d.ts +3 -3
- package/dist/icon.js +1 -1
- package/dist/icons.d.ts +1 -1
- package/dist/{index-DFBA9X1i.d.ts → index-DU3SQJ46.d.ts} +4 -3
- package/dist/{index-A354MgUP.d.ts → index-ddHz7L9f.d.ts} +4 -4
- package/dist/input.d.ts +1 -1
- package/dist/input.js +1 -1
- package/dist/input.js.map +1 -1
- package/dist/kbd-B0wWeV_0.js +2 -0
- package/dist/{kbd-GS-e4ICt.js.map → kbd-B0wWeV_0.js.map} +1 -1
- package/dist/kbd.js +1 -1
- package/dist/label.js +1 -1
- package/dist/label.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/media-object.js +1 -1
- package/dist/media-object.js.map +1 -1
- package/dist/multi-select.js +1 -1
- package/dist/pagination.d.ts +1 -1
- package/dist/pagination.js +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/popover.d.ts +12 -0
- package/dist/popover.js +1 -1
- package/dist/popover.js.map +1 -1
- package/dist/{primitive-pggbsddf.js → primitive-tXm_8n_t.js} +2 -2
- package/dist/{primitive-pggbsddf.js.map → primitive-tXm_8n_t.js.map} +1 -1
- package/dist/progress.js +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/radio-group.js.map +1 -1
- package/dist/select-LJmfG--I.js +2 -0
- package/dist/select-LJmfG--I.js.map +1 -0
- package/dist/select.js +1 -1
- package/dist/separator-DyOGgFCs.js +2 -0
- package/dist/separator-DyOGgFCs.js.map +1 -0
- package/dist/separator.js +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sheet.js.map +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/skip-to-main-link.js +1 -1
- package/dist/skip-to-main-link.js.map +1 -1
- package/dist/split-button.d.ts +1 -1
- package/dist/split-button.js +1 -1
- package/dist/{svg-only-DnZldAY9.js → svg-only-7gYlsX8f.js} +2 -2
- package/dist/{svg-only-DnZldAY9.js.map → svg-only-7gYlsX8f.js.map} +1 -1
- package/dist/{svg-only-B-xzpaiu.d.ts → svg-only-BnnbLx6R.d.ts} +2 -2
- package/dist/switch.js +1 -1
- package/dist/switch.js.map +1 -1
- package/dist/table-12T25gGa.js +2 -0
- package/dist/table-12T25gGa.js.map +1 -0
- package/dist/table.js +1 -1
- package/dist/tabs.js +1 -1
- package/dist/tabs.js.map +1 -1
- package/dist/text-area.js +1 -1
- package/dist/text-area.js.map +1 -1
- package/dist/toast-CGnquSKO.js +2 -0
- package/dist/toast-CGnquSKO.js.map +1 -0
- package/dist/toast.d.ts +1 -1
- package/dist/toast.js +1 -1
- package/dist/tooltip.d.ts +9 -2
- package/dist/tooltip.js.map +1 -1
- package/dist/types-DEYyl5LX.d.ts +30 -0
- package/package.json +1 -1
- package/dist/anchor-BtIZueBA.js +0 -2
- package/dist/anchor-BtIZueBA.js.map +0 -1
- package/dist/button-DdrxOnUb.js +0 -2
- package/dist/button-DdrxOnUb.js.map +0 -1
- package/dist/dialog-Cw3E0Wr9.js +0 -2
- package/dist/dialog-Cw3E0Wr9.js.map +0 -1
- package/dist/dropdown-menu-Bfi9ODPB.js +0 -2
- package/dist/dropdown-menu-Bfi9ODPB.js.map +0 -1
- package/dist/icon-BMH0fD_b.js +0 -2
- package/dist/kbd-GS-e4ICt.js +0 -2
- package/dist/select-BPzMl3gm.js +0 -2
- package/dist/select-BPzMl3gm.js.map +0 -1
- package/dist/separator-Yk9hMn8E.js +0 -2
- package/dist/separator-Yk9hMn8E.js.map +0 -1
- package/dist/table-BMGcRJlk.js +0 -2
- package/dist/table-BMGcRJlk.js.map +0 -1
- package/dist/toast-BhAyUXKL.js +0 -2
- package/dist/toast-BhAyUXKL.js.map +0 -1
- package/dist/types-zKzi66a6.d.ts +0 -9
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as SvgAttributes } from "./types-
|
|
1
|
+
import { t as SvgAttributes } from "./types-DEYyl5LX.js";
|
|
2
2
|
import * as _$react from "react";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
|
|
@@ -24,4 +24,4 @@ type IconProps = Omit<SvgAttributes, "children"> & {
|
|
|
24
24
|
declare const Icon: _$react.ForwardRefExoticComponent<Omit<IconProps, "ref"> & _$react.RefAttributes<SVGSVGElement>>;
|
|
25
25
|
//#endregion
|
|
26
26
|
export { IconProps as n, Icon as t };
|
|
27
|
-
//# sourceMappingURL=icon-
|
|
27
|
+
//# sourceMappingURL=icon-C0YAAaLZ.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./svg-only-7gYlsX8f.js";import{forwardRef as n}from"react";import{jsx as r}from"react/jsx-runtime";const i=n(({className:n,style:i,svg:a,...o},s)=>r(t,{ref:s,"data-slot":`icon`,className:e(`size-5`,n),style:i,svg:a,...o}));i.displayName=`Icon`;export{i as t};
|
|
2
|
+
//# sourceMappingURL=icon-bWc5yC3-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-
|
|
1
|
+
{"version":3,"file":"icon-bWc5yC3-.js","names":[],"sources":["../src/components/icon/icon.tsx"],"sourcesContent":["import { type ComponentRef, type ReactNode, forwardRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { SvgOnly } from \"./svg-only.js\";\nimport type { SvgAttributes } from \"./types.js\";\n\ntype IconProps = Omit<SvgAttributes, \"children\"> & {\n\t/**\n\t * A single SVG icon element.\n\t */\n\tsvg: ReactNode;\n};\n\n/**\n * Decorates an svg icon with automatic sizing styles and a `shrink-0` class.\n *\n * @see https://mantle.ngrok.com/components/icon\n *\n * @example\n * ```tsx\n * import { ShrimpIcon } from \"@phosphor-icons/react/Shrimp\";\n *\n * <Icon svg={<ShrimpIcon />} />\n * ```\n */\nconst Icon = forwardRef<ComponentRef<\"svg\">, IconProps>(\n\t({ className, style, svg, ...props }, ref) => (\n\t\t<SvgOnly\n\t\t\tref={ref}\n\t\t\tdata-slot=\"icon\"\n\t\t\tclassName={cx(\"size-5\", className)}\n\t\t\tstyle={style}\n\t\t\tsvg={svg}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nIcon.displayName = \"Icon\";\n\nexport {\n\t//,\n\tIcon,\n};\n\nexport type {\n\t//,\n\tIconProps,\n};\n"],"mappings":"sJAwBA,MAAM,EAAO,GACX,CAAE,YAAW,QAAO,MAAK,GAAG,GAAS,IACrC,EAAC,EAAD,CACM,MACL,YAAU,OACV,UAAW,EAAG,SAAU,EAAU,CAC3B,QACF,MACL,GAAI,EACH,CAAA,CAEH,CACD,EAAK,YAAc"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-
|
|
2
|
-
//# sourceMappingURL=icon-button-
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-bWc5yC3-.js";import{t as n}from"./booleanish-CBGdPL3Q.js";import{t as r}from"./slot-D_ZUrdEW.js";import{Children as i,cloneElement as a,forwardRef as o,isValidElement as s}from"react";import c from"tiny-invariant";import{Fragment as l,jsx as u,jsxs as d}from"react/jsx-runtime";import{cva as f}from"class-variance-authority";import{CircleNotchIcon as p}from"@phosphor-icons/react/CircleNotch";const m=e(`icon-button`,`inline-flex shrink-0 items-center justify-center rounded-[var(--icon-button-border-radius,0.375rem)] border`,`focus:outline-hidden focus-visible:ring-4`,`disabled:cursor-default disabled:opacity-50`,`not-disabled:active:scale-97 ease-out transition-transform duration-150`),h=f(m,{variants:{appearance:{ghost:`text-strong focus-visible:ring-focus-accent not-disabled:hover:bg-neutral-500/10 not-disabled:hover:text-strong border-transparent`,outlined:`border-form bg-form text-strong focus-visible:border-accent-600 focus-visible:ring-focus-accent not-disabled:hover:border-neutral-400 not-disabled:hover:bg-form-hover not-disabled:hover:text-strong focus-visible:not-disabled:hover:border-accent-600 focus-visible:not-disabled:active:border-accent-600`},isLoading:{false:``,true:`opacity-50`},size:{xs:`size-6`,sm:`size-7`,md:`size-9`}},defaultVariants:{appearance:`outlined`,size:`md`}}),g=o(({"aria-disabled":o,appearance:f,asChild:m=!1,children:g,className:_,disabled:v,icon:y,isLoading:b=!1,label:x,size:S,type:C,...w},T)=>{let E=n(o??v??b),D=b?u(p,{className:`animate-spin`}):y,O={"aria-disabled":E,"data-slot":`icon-button`,className:e(h({appearance:f,isLoading:b,size:S}),_),"data-appearance":f,"data-disabled":E,"data-icon-button":!0,"data-loading":b,"data-size":S,disabled:E,ref:T,...w},k=d(l,{children:[u(`span`,{className:`sr-only`,children:x}),u(t,{svg:D})]});return m?(c(s(g)&&i.only(g),"When using `asChild`, IconButton must be passed a single child as a JSX tag."),u(r,{...O,children:a(g,{},k)})):u(`button`,{...O,type:C,children:k})});g.displayName=`IconButton`;export{m as n,h as r,g as t};
|
|
2
|
+
//# sourceMappingURL=icon-button-ZKN0sRIJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button-
|
|
1
|
+
{"version":3,"file":"icon-button-ZKN0sRIJ.js","names":[],"sources":["../src/components/button/icon-button.tsx"],"sourcesContent":["import { CircleNotchIcon } from \"@phosphor-icons/react/CircleNotch\";\nimport { cva } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { Children, cloneElement, forwardRef, isValidElement } from \"react\";\nimport invariant from \"tiny-invariant\";\nimport type { VariantProps, WithAsChild } from \"../../types/index.js\";\nimport { parseBooleanish } from \"../../types/index.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Icon } from \"../icon/index.js\";\nimport { Slot } from \"../slot/index.js\";\n\nconst baseIconButtonClasses = cx(\n\t\"icon-button\",\n\t\"inline-flex shrink-0 items-center justify-center rounded-[var(--icon-button-border-radius,0.375rem)] border\",\n\t\"focus:outline-hidden focus-visible:ring-4\",\n\t\"disabled:cursor-default disabled:opacity-50\",\n\t\"not-disabled:active:scale-97 ease-out transition-transform duration-150\",\n);\n\nconst iconButtonVariants = cva(baseIconButtonClasses, {\n\tvariants: {\n\t\t/**\n\t\t * Defines the visual style of the Button.\n\t\t */\n\t\tappearance: {\n\t\t\tghost:\n\t\t\t\t\"text-strong focus-visible:ring-focus-accent not-disabled:hover:bg-neutral-500/10 not-disabled:hover:text-strong border-transparent\",\n\t\t\toutlined:\n\t\t\t\t\"border-form bg-form text-strong focus-visible:border-accent-600 focus-visible:ring-focus-accent not-disabled:hover:border-neutral-400 not-disabled:hover:bg-form-hover not-disabled:hover:text-strong focus-visible:not-disabled:hover:border-accent-600 focus-visible:not-disabled:active:border-accent-600\",\n\t\t},\n\t\t/**\n\t\t * Whether or not the button is in a loading state, default `false`. Setting `isLoading` will\n\t\t * replace the `icon` with a spinner.\n\t\t * It will also disable user interaction with the button and set `aria-disabled`.\n\t\t */\n\t\tisLoading: {\n\t\t\tfalse: \"\",\n\t\t\ttrue: \"opacity-50\",\n\t\t},\n\t\t/**\n\t\t * The size of the IconButton.\n\t\t */\n\t\tsize: {\n\t\t\txs: \"size-6\",\n\t\t\tsm: \"size-7\",\n\t\t\tmd: \"size-9\",\n\t\t},\n\t},\n\tdefaultVariants: {\n\t\tappearance: \"outlined\",\n\t\tsize: \"md\",\n\t},\n});\n\ntype IconButtonVariants = VariantProps<typeof iconButtonVariants>;\n\n/**\n * The props for the `Button` component.\n */\ntype IconButtonProps = ButtonHTMLAttributes<HTMLButtonElement> &\n\tWithAsChild &\n\tIconButtonVariants & {\n\t\t/**\n\t\t * The accessible label for the icon. This label will be visually hidden but announced to screen reader users, similar to alt text for img tags.\n\t\t */\n\t\tlabel: string;\n\t\t/**\n\t\t * An icon to render inside the button. If the `state` is `\"pending\"`, then\n\t\t * the icon will automatically be replaced with a spinner.\n\t\t */\n\t\ticon: ReactNode;\n\t} & (\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * Use the `asChild` prop to compose Radix's functionality onto alternative\n\t\t\t\t * element types or your own React components.\n\t\t\t\t *\n\t\t\t\t * When `asChild` is set to `true`, mantle will not render a default DOM\n\t\t\t\t * element, instead cloning the component's child and passing it the props and\n\t\t\t\t * behavior required to make it functional.\n\t\t\t\t *\n\t\t\t\t * asChild can be used as deeply as you need to. This means it is a great way\n\t\t\t\t * to compose multiple primitive's behavior together.\n\t\t\t\t *\n\t\t\t\t * @see https://www.radix-ui.com/docs/primitives/guides/composition#composition\n\t\t\t\t */\n\t\t\t\tasChild: true;\n\t\t\t\t/**\n\t\t\t\t * The default behavior of the button. Possible values are: `\"button\"`, `\"submit\"`, and `\"reset\"`.\n\t\t\t\t *\n\t\t\t\t * if `asChild` is NOT used: Unlike the native `<button>` element, this prop is required and has no default value.\n\t\t\t\t *\n\t\t\t\t * If `asChild` IS used: This prop HAS NO EFFECT, is REMOVED, and has no default value. This is because we do not want the `button` `type` to automatically merge with any child anchor `type` attribute because the `anchor` `type` is _strictly different_ than the `button` type, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#type\n\t\t\t\t *\n\t\t\t\t * @enum\n\t\t\t\t * - `\"button\"`: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.\n\t\t\t\t * - `\"reset\"`: The button resets all the controls to their initial values.\n\t\t\t\t * - `\"submit\"`: The button submits the form data to the server.\n\t\t\t\t *\n\t\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type\n\t\t\t\t */\n\t\t\t\ttype?: ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n\t\t }\n\t\t| {\n\t\t\t\tasChild?: false | undefined;\n\t\t\t\t/**\n\t\t\t\t * The default behavior of the button. Possible values are: `\"button\"`, `\"submit\"`, and `\"reset\"`.\n\t\t\t\t *\n\t\t\t\t * if `asChild` is NOT used: Unlike the native `<button>` element, this prop is required and has no default value.\n\t\t\t\t *\n\t\t\t\t * If `asChild` IS used: This prop HAS NO EFFECT, is REMOVED, and has no default value. This is because we do not want the `button` `type` to automatically merge with any child anchor `type` attribute because the `anchor` `type` is _strictly different_ than the `button` type, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#type\n\t\t\t\t *\n\t\t\t\t * @enum\n\t\t\t\t * - `\"button\"`: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.\n\t\t\t\t * - `\"reset\"`: The button resets all the controls to their initial values.\n\t\t\t\t * - `\"submit\"`: The button submits the form data to the server.\n\t\t\t\t *\n\t\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type\n\t\t\t\t */\n\t\t\t\ttype: Exclude<ButtonHTMLAttributes<HTMLButtonElement>[\"type\"], undefined>;\n\t\t }\n\t);\n\n/**\n * Renders a button or a component that looks like a button, an interactive\n * element activated by a user with a mouse, keyboard, finger, voice command, or\n * other assistive technology. Once activated, it then performs an action, such\n * as submitting a form or opening a dialog.\n * Renders only a single icon as children with an accessible, screen-reader-only label.\n *\n * @see https://mantle.ngrok.com/components/button\n *\n * @example\n * ```tsx\n * <IconButton\n * type=\"button\"\n * icon={<TrashIcon />}\n * label=\"Delete item\"\n * appearance=\"ghost\"\n * size=\"sm\"\n * />\n * ```\n */\nconst IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n\t(\n\t\t{\n\t\t\t\"aria-disabled\": _ariaDisabled,\n\t\t\tappearance,\n\t\t\tasChild = false,\n\t\t\tchildren,\n\t\t\tclassName,\n\t\t\tdisabled: _disabled,\n\t\t\ticon: propIcon,\n\t\t\tisLoading = false,\n\t\t\tlabel,\n\t\t\tsize,\n\t\t\ttype,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst disabled = parseBooleanish(_ariaDisabled ?? _disabled ?? isLoading);\n\t\tconst icon = isLoading ? <CircleNotchIcon className=\"animate-spin\" /> : propIcon;\n\n\t\tconst buttonProps = {\n\t\t\t\"aria-disabled\": disabled,\n\t\t\t\"data-slot\": \"icon-button\",\n\t\t\tclassName: cx(iconButtonVariants({ appearance, isLoading, size }), className),\n\t\t\t\"data-appearance\": appearance,\n\t\t\t\"data-disabled\": disabled,\n\t\t\t\"data-icon-button\": true,\n\t\t\t\"data-loading\": isLoading,\n\t\t\t\"data-size\": size,\n\t\t\tdisabled,\n\t\t\tref,\n\t\t\t...props,\n\t\t};\n\n\t\tconst innerChildren = (\n\t\t\t<>\n\t\t\t\t<span className=\"sr-only\">{label}</span>\n\t\t\t\t<Icon svg={icon} />\n\t\t\t</>\n\t\t);\n\n\t\tif (asChild) {\n\t\t\tinvariant(\n\t\t\t\tisValidElement(children) && Children.only(children),\n\t\t\t\t\"When using `asChild`, IconButton must be passed a single child as a JSX tag.\",\n\t\t\t);\n\n\t\t\treturn <Slot {...buttonProps}>{cloneElement(children, {}, innerChildren)}</Slot>;\n\t\t}\n\n\t\treturn (\n\t\t\t<button {...buttonProps} type={type}>\n\t\t\t\t{innerChildren}\n\t\t\t</button>\n\t\t);\n\t},\n);\nIconButton.displayName = \"IconButton\";\n\nexport {\n\tbaseIconButtonClasses,\n\t//,\n\tIconButton,\n\ticonButtonVariants,\n};\n\nexport type {\n\t//,\n\tIconButtonProps,\n};\n"],"mappings":"mcAWA,MAAM,EAAwB,EAC7B,cACA,8GACA,4CACA,8CACA,0EACA,CAEK,EAAqB,EAAI,EAAuB,CACrD,SAAU,CAIT,WAAY,CACX,MACC,qIACD,SACC,+SACD,CAMD,UAAW,CACV,MAAO,GACP,KAAM,aACN,CAID,KAAM,CACL,GAAI,SACJ,GAAI,SACJ,GAAI,SACJ,CACD,CACD,gBAAiB,CAChB,WAAY,WACZ,KAAM,KACN,CACD,CAAC,CA2FI,EAAa,GAEjB,CACC,gBAAiB,EACjB,aACA,UAAU,GACV,WACA,YACA,SAAU,EACV,KAAM,EACN,YAAY,GACZ,QACA,OACA,OACA,GAAG,GAEJ,IACI,CACJ,IAAM,EAAW,EAAgB,GAAiB,GAAa,EAAU,CACnE,EAAO,EAAY,EAAC,EAAD,CAAiB,UAAU,eAAiB,CAAA,CAAG,EAElE,EAAc,CACnB,gBAAiB,EACjB,YAAa,cACb,UAAW,EAAG,EAAmB,CAAE,aAAY,YAAW,OAAM,CAAC,CAAE,EAAU,CAC7E,kBAAmB,EACnB,gBAAiB,EACjB,mBAAoB,GACpB,eAAgB,EAChB,YAAa,EACb,WACA,MACA,GAAG,EACH,CAEK,EACL,EAAA,EAAA,CAAA,SAAA,CACC,EAAC,OAAD,CAAM,UAAU,mBAAW,EAAa,CAAA,CACxC,EAAC,EAAD,CAAM,IAAK,EAAQ,CAAA,CACjB,CAAA,CAAA,CAYJ,OATI,GACH,EACC,EAAe,EAAS,EAAI,EAAS,KAAK,EAAS,CACnD,+EACA,CAEM,EAAC,EAAD,CAAM,GAAI,WAAc,EAAa,EAAU,EAAE,CAAE,EAAc,CAAQ,CAAA,EAIhF,EAAC,SAAD,CAAQ,GAAI,EAAmB,gBAC7B,EACO,CAAA,EAGX,CACD,EAAW,YAAc"}
|
package/dist/icon.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as SvgAttributes } from "./types-
|
|
2
|
-
import { n as IconProps, t as Icon } from "./icon-
|
|
3
|
-
import { n as SvgOnlyProps, t as SvgOnly } from "./svg-only-
|
|
1
|
+
import { t as SvgAttributes } from "./types-DEYyl5LX.js";
|
|
2
|
+
import { n as IconProps, t as Icon } from "./icon-C0YAAaLZ.js";
|
|
3
|
+
import { n as SvgOnlyProps, t as SvgOnly } from "./svg-only-BnnbLx6R.js";
|
|
4
4
|
export { Icon, type IconProps, type SvgAttributes, SvgOnly, type SvgOnlyProps };
|
package/dist/icon.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./svg-only-
|
|
1
|
+
import{t as e}from"./svg-only-7gYlsX8f.js";import{t}from"./icon-bWc5yC3-.js";export{t as Icon,e as SvgOnly};
|
package/dist/icons.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as SvgAttributes } from "./types-
|
|
1
|
+
import { t as SvgAttributes } from "./types-DEYyl5LX.js";
|
|
2
2
|
import { a as AlphanumericSortingDirection, c as TimeSortingDirection, o as SortingDirection, s as SortingMode } from "./direction-Jk7BkzGo.js";
|
|
3
3
|
import { i as Theme } from "./themes-DXb8Tk74.js";
|
|
4
4
|
import { ComponentProps } from "react";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as WithAsChild } from "./as-child-CJ2vTesV.js";
|
|
1
2
|
import { t as VariantProps } from "./variant-props-DszdagRm.js";
|
|
2
3
|
import * as _$react from "react";
|
|
3
4
|
import { ComponentProps } from "react";
|
|
@@ -5,10 +6,10 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
|
|
|
5
6
|
|
|
6
7
|
//#region src/components/button/button-group.d.ts
|
|
7
8
|
declare const buttonGroupVariants: (props?: ({
|
|
8
|
-
appearance?: "
|
|
9
|
+
appearance?: "panel" | "ghost" | "outlined" | null | undefined;
|
|
9
10
|
} & _$class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
10
11
|
type ButtonGroupVariants = VariantProps<typeof buttonGroupVariants>;
|
|
11
|
-
type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants;
|
|
12
|
+
type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants & WithAsChild;
|
|
12
13
|
/**
|
|
13
14
|
* A contained group of related buttons.
|
|
14
15
|
*
|
|
@@ -26,4 +27,4 @@ type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants;
|
|
|
26
27
|
declare const ButtonGroup: _$react.ForwardRefExoticComponent<Omit<ButtonGroupProps, "ref"> & _$react.RefAttributes<HTMLDivElement>>;
|
|
27
28
|
//#endregion
|
|
28
29
|
export { ButtonGroupProps as n, ButtonGroup as t };
|
|
29
|
-
//# sourceMappingURL=index-
|
|
30
|
+
//# sourceMappingURL=index-DU3SQJ46.d.ts.map
|
|
@@ -23,7 +23,7 @@ type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "
|
|
|
23
23
|
* />
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
|
-
declare const Input: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "
|
|
26
|
+
declare const Input: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithAutoComplete & WithInputType & WithValidation & {
|
|
27
27
|
children?: _$react.ReactNode | undefined;
|
|
28
28
|
} & _$react.RefAttributes<HTMLInputElement>>;
|
|
29
29
|
type InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & BaseProps;
|
|
@@ -41,7 +41,7 @@ type InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComple
|
|
|
41
41
|
* </Input>
|
|
42
42
|
* ```
|
|
43
43
|
*/
|
|
44
|
-
declare const InputCapture: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "
|
|
44
|
+
declare const InputCapture: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithAutoComplete & WithInputType & WithValidation & _$react.RefAttributes<HTMLInputElement>>;
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region src/components/input/password-input.d.ts
|
|
47
47
|
type PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithValidation & WithAutoComplete & {
|
|
@@ -70,7 +70,7 @@ type PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoCompl
|
|
|
70
70
|
* />
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
|
-
declare const PasswordInput: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "
|
|
73
|
+
declare const PasswordInput: _$react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithValidation & WithAutoComplete & {
|
|
74
74
|
/**
|
|
75
75
|
* Callback for when the visibility of the password value changes.
|
|
76
76
|
*/
|
|
@@ -100,4 +100,4 @@ declare const PasswordInput: _$react.ForwardRefExoticComponent<Omit<InputHTMLAtt
|
|
|
100
100
|
declare function isInput(value: unknown): value is HTMLInputElement;
|
|
101
101
|
//#endregion
|
|
102
102
|
export { InputCapture as a, Input as i, PasswordInput as n, InputCaptureProps as o, PasswordInputProps as r, InputProps as s, isInput as t };
|
|
103
|
-
//# sourceMappingURL=index-
|
|
103
|
+
//# sourceMappingURL=index-ddHz7L9f.d.ts.map
|
package/dist/input.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { a as WithInputType, i as WithAutoComplete, n as InputType, o as WithValidation, r as Validation, t as AutoComplete } from "./types-BeTbgoJd.js";
|
|
2
|
-
import { a as InputCapture, i as Input, n as PasswordInput, o as InputCaptureProps, r as PasswordInputProps, s as InputProps, t as isInput } from "./index-
|
|
2
|
+
import { a as InputCapture, i as Input, n as PasswordInput, o as InputCaptureProps, r as PasswordInputProps, s as InputProps, t as isInput } from "./index-ddHz7L9f.js";
|
|
3
3
|
export { AutoComplete, Input, InputCapture, InputCaptureProps, InputProps, InputType, PasswordInput, PasswordInputProps, Validation, WithAutoComplete, WithInputType, WithValidation, isInput };
|
package/dist/input.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-bWc5yC3-.js";import{t as n}from"./compose-refs-DFIaEnQH.js";import{t as r}from"./use-prefers-reduced-motion-BcwST13S.js";import{t as i}from"./is-input-Bh1rQhX3.js";import{createContext as a,forwardRef as o,useContext as s,useEffect as c,useRef as l,useState as u}from"react";import d from"clsx";import{jsx as f,jsxs as p}from"react/jsx-runtime";import{CheckCircleIcon as m}from"@phosphor-icons/react/CheckCircle";import{WarningIcon as h}from"@phosphor-icons/react/Warning";import{WarningDiamondIcon as g}from"@phosphor-icons/react/WarningDiamond";import{EyeIcon as _}from"@phosphor-icons/react/Eye";import{EyeClosedIcon as v}from"@phosphor-icons/react/EyeClosed";import{flushSync as y}from"react-dom";const b=o(({children:e,className:t,...n},r)=>{let i=!!e,a=l(null);return i?f(C,{className:t,forwardedRef:r,innerRef:a,...n,children:e}):f(C,{...n,className:t,forwardedRef:r,innerRef:a,children:f(x,{...n})})});b.displayName=`Input`;const x=o(({"aria-invalid":t,className:r,validation:i,...a},o)=>{let{"aria-invalid":c,forwardedRef:l,innerRef:u,validation:d,...p}=s(S),m=d??i,h=(typeof m==`function`?m():m)||void 0,g=c??t??m===`error`,_={...p,...a,type:a.type??p.type??`text`};return f(`input`,{"aria-invalid":g,"data-slot":`input-capture`,"data-validation":h,className:e(`placeholder:text-placeholder min-w-0 flex-1 bg-transparent text-left autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] focus:outline-hidden`,r),ref:n(o,l,u),..._})});x.displayName=`InputCapture`;const S=a({validation:void 0,innerRef:{current:null}}),C=({"aria-invalid":t,"aria-disabled":n,"data-slot":r=`input`,children:i,className:a,disabled:o,forwardedRef:s,innerRef:c,style:l,type:u,validation:d,...m})=>{let h=t!=null&&t!==`false`?`error`:typeof d==`function`?d():d;return f(S.Provider,{value:{"aria-invalid":t,"aria-disabled":n,disabled:o,type:u,validation:h,...m,forwardedRef:s,innerRef:c},children:p(`div`,{role:`none`,"data-slot":r,"data-disabled":(o??n)||void 0,"data-validation":h||void 0,className:e(`pointer-coarse:text-base h-9 text-sm`,`bg-form relative flex w-full items-center gap-1.5 rounded-md border px-3 py-2 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-within:outline-hidden focus-within:ring-4`,`data-disabled:opacity-50`,`has-[input:not(:first-child)]:ps-2.5 has-[input:not(:last-child)]:pe-2.5 [&>:not(input)]:shrink-0 [&_svg]:size-5`,`border-form text-strong focus-within:border-accent-600 focus-within:ring-focus-accent`,`data-validation-success:border-success-600 focus-within:data-validation-success:border-success-600 focus-within:data-validation-success:ring-focus-success`,`data-validation-warning:border-warning-600 focus-within:data-validation-warning:border-warning-600 focus-within:data-validation-warning:ring-focus-warning`,`data-validation-error:border-danger-600 focus-within:data-validation-error:border-danger-600 focus-within:data-validation-error:ring-focus-danger`,`autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] has-autofill:bg-blue-50 has-autofill:[-webkit-text-fill-color:var(--text-color-strong)]`,a),onMouseDown:e=>{e.target!==c?.current&&e.preventDefault()},onClick:()=>{c?.current?.focus()},onKeyDown:()=>{c?.current!==document.activeElement&&c?.current?.focus()},style:l,children:[i,f(w,{name:m.name,validation:h})]})})};C.displayName=`InputContainer`;const w=({name:e,validation:n})=>{switch(n){case`error`:return p(`div`,{className:`text-danger-600 order-last select-none`,children:[f(`span`,{className:`sr-only`,children:d(`The value entered for the`,e,`input has failed validation.`)}),f(t,{svg:f(h,{"aria-hidden":!0,weight:`fill`})})]});case`success`:return f(`div`,{className:`text-success-600 order-last select-none`,children:f(t,{svg:f(m,{weight:`fill`})})});case`warning`:return f(`div`,{className:`text-warning-600 order-last select-none`,children:f(t,{svg:f(g,{weight:`fill`})})});default:return null}};w.displayName=`ValidationFeedback`;const T=o(({onValueVisibilityChange:e,showValue:n=!1,...i},a)=>{let[o,s]=u(n),d=o?`text`:`password`,m=o?_:v,h=l(null),g=l(null);return c(()=>{s(n)},[n]),p(b,{"data-slot":`password-input`,type:d,ref:a,...i,children:[f(x,{}),p(`button`,{type:`button`,tabIndex:-1,className:`text-body hover:text-strong ml-1 cursor-pointer bg-inherit p-0`,onClick:()=>{g.current&&=(g.current.cancel(),null);let t=!o;y(()=>{s(t)}),e?.(t);let n=h.current;n&&!r()&&(g.current=n.animate([{transform:`scaleY(0)`},{transform:`scaleY(1)`}],{duration:200,easing:`ease-out`}),g.current.onfinish=()=>{g.current=null})},children:[p(`span`,{className:`sr-only`,children:[`Turn password visibility `,o?`off`:`on`]}),f(t,{ref:h,svg:f(m,{"aria-hidden":!0})})]})]})});T.displayName=`PasswordInput`;export{b as Input,x as InputCapture,T as PasswordInput,i as isInput};
|
|
2
2
|
//# sourceMappingURL=input.js.map
|
package/dist/input.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","names":["clsx"],"sources":["../src/components/input/input.tsx","../src/components/input/password-input.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckCircleIcon } from \"@phosphor-icons/react/CheckCircle\";\nimport { WarningIcon } from \"@phosphor-icons/react/Warning\";\nimport { WarningDiamondIcon } from \"@phosphor-icons/react/WarningDiamond\";\nimport clsx from \"clsx\";\nimport type {\n\tComponentRef,\n\tForwardedRef,\n\tInputHTMLAttributes,\n\tMutableRefObject,\n\tPropsWithChildren,\n} from \"react\";\nimport { createContext, forwardRef, useContext, useRef } from \"react\";\nimport { composeRefs } from \"../../utils/compose-refs/compose-refs.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport type { Validation, WithAutoComplete, WithInputType, WithValidation } from \"./types.js\";\n\ntype BaseProps = WithAutoComplete & WithInputType & WithValidation;\n\n/**\n * The props for the `Input` component.\n */\ntype InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps &\n\tPropsWithChildren;\n\n/**\n * Used to create interactive controls for web-based forms in order to accept data from the user.\n * A versatile input element that supports various types, validation states, and can be composed with other elements.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * validation=\"success\"\n * />\n * ```\n */\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n\t({ children, className, ...props }, forwardedRef) => {\n\t\tconst hasChildren = Boolean(children);\n\t\tconst innerRef = useRef<ComponentRef<\"input\">>(null);\n\n\t\tif (hasChildren) {\n\t\t\treturn (\n\t\t\t\t<InputContainer\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\t\tinnerRef={innerRef}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</InputContainer>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<InputContainer\n\t\t\t\t{...props}\n\t\t\t\tclassName={className}\n\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\tinnerRef={innerRef}\n\t\t\t>\n\t\t\t\t<InputCapture {...props} />\n\t\t\t</InputContainer>\n\t\t);\n\t},\n);\nInput.displayName = \"Input\";\n\ntype InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps;\n\n/**\n * The actual <input /> element that captures user input.\n * Used internally by Input component or when you need direct control over the input element.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input>\n * <InputCapture />\n * <Icon svg={<SearchIcon />} />\n * </Input>\n * ```\n */\nconst InputCapture = forwardRef<HTMLInputElement, InputCaptureProps>(\n\t({ \"aria-invalid\": _ariaInvalid, className, validation: _validation, ...restProps }, ref) => {\n\t\tconst {\n\t\t\t\"aria-invalid\": ctxAriaInvalid,\n\t\t\tforwardedRef: ctxForwardedRef,\n\t\t\tinnerRef: ctxInnerRef,\n\t\t\tvalidation: ctxValidation,\n\t\t\t...ctx\n\t\t} = useContext(InputContext);\n\n\t\tconst validation = ctxValidation ?? _validation;\n\t\tconst validationValue =\n\t\t\t(typeof validation === \"function\" ? validation() : validation) || undefined;\n\t\tconst ariaInvalid = ctxAriaInvalid ?? _ariaInvalid ?? validation === \"error\";\n\t\tconst props = {\n\t\t\t...ctx,\n\t\t\t...restProps,\n\t\t\ttype: restProps.type ?? ctx.type ?? \"text\",\n\t\t};\n\n\t\treturn (\n\t\t\t<input\n\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\tdata-validation={validationValue}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"placeholder:text-placeholder min-w-0 flex-1 bg-transparent text-left autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] focus:outline-hidden\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={composeRefs(ref, ctxForwardedRef, ctxInnerRef)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputCapture.displayName = \"InputCapture\";\n\ntype InputContextType = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps & {\n\t\t/**\n\t\t * inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * forwarded ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef?: ForwardedRef<HTMLInputElement>;\n\t};\n\nconst InputContext = createContext<InputContextType>({\n\tvalidation: undefined,\n\tinnerRef: { current: null },\n});\n\ntype InputContainerProps = InputHTMLAttributes<HTMLInputElement> &\n\tBaseProps & {\n\t\t/**\n\t\t * @private inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * @private ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef: ForwardedRef<HTMLInputElement>;\n\t};\n\n/**\n * The container for the input element.\n */\nconst InputContainer = ({\n\t\"aria-invalid\": _ariaInvalid,\n\t\"aria-disabled\": _ariaDisabled,\n\tchildren,\n\tclassName,\n\tdisabled,\n\tforwardedRef,\n\tinnerRef,\n\tstyle,\n\ttype,\n\tvalidation: _validation,\n\t...props\n}: InputContainerProps) => {\n\tconst isInvalid = _ariaInvalid != null && _ariaInvalid !== \"false\";\n\tconst validation = isInvalid\n\t\t? \"error\"\n\t\t: typeof _validation === \"function\"\n\t\t\t? _validation()\n\t\t\t: _validation;\n\treturn (\n\t\t<InputContext.Provider\n\t\t\tvalue={{\n\t\t\t\t\"aria-invalid\": _ariaInvalid,\n\t\t\t\t\"aria-disabled\": _ariaDisabled,\n\t\t\t\tdisabled,\n\t\t\t\ttype,\n\t\t\t\tvalidation,\n\t\t\t\t...props,\n\t\t\t\tforwardedRef,\n\t\t\t\tinnerRef,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\trole=\"none\"\n\t\t\t\tdata-disabled={(disabled ?? _ariaDisabled) || undefined}\n\t\t\t\tdata-validation={validation || undefined}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"pointer-coarse:text-base h-9 text-sm\",\n\t\t\t\t\t\"bg-form relative flex w-full items-center gap-1.5 rounded-md border px-3 py-2 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-within:outline-hidden focus-within:ring-4\",\n\t\t\t\t\t\"data-disabled:opacity-50\",\n\t\t\t\t\t\"has-[input:not(:first-child)]:ps-2.5 has-[input:not(:last-child)]:pe-2.5 [&>:not(input)]:shrink-0 [&_svg]:size-5\",\n\t\t\t\t\t\"border-form text-strong focus-within:border-accent-600 focus-within:ring-focus-accent\",\n\t\t\t\t\t\"data-validation-success:border-success-600 focus-within:data-validation-success:border-success-600 focus-within:data-validation-success:ring-focus-success\",\n\t\t\t\t\t\"data-validation-warning:border-warning-600 focus-within:data-validation-warning:border-warning-600 focus-within:data-validation-warning:ring-focus-warning\",\n\t\t\t\t\t\"data-validation-error:border-danger-600 focus-within:data-validation-error:border-danger-600 focus-within:data-validation-error:ring-focus-danger\",\n\t\t\t\t\t\"autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] has-autofill:bg-blue-50 has-autofill:[-webkit-text-fill-color:var(--text-color-strong)]\", // Autofill styling on the input itself and any children with autofill styling\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t// Prevent mousedown on non-input children (icons, buttons, etc.) from\n\t\t\t\t\t// blurring the input, which would cause the focus ring to flicker.\n\t\t\t\t\tif (event.target !== innerRef?.current) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t}}\n\t\t\t\tonKeyDown={() => {\n\t\t\t\t\tif (innerRef?.current !== document.activeElement) {\n\t\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<ValidationFeedback name={props.name} validation={validation} />\n\t\t\t</div>\n\t\t</InputContext.Provider>\n\t);\n};\nInputContainer.displayName = \"InputContainer\";\n\nexport { Input, InputCapture };\nexport type { InputProps, InputCaptureProps };\n\nconst ValidationFeedback = ({\n\tname,\n\tvalidation,\n}: {\n\tname?: string;\n\tvalidation: Validation | undefined;\n}) => {\n\tswitch (validation) {\n\t\tcase \"error\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-danger-600 order-last select-none\">\n\t\t\t\t\t<span className=\"sr-only\">\n\t\t\t\t\t\t{clsx(\"The value entered for the\", name, \"input has failed validation.\")}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Icon svg={<WarningIcon aria-hidden weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"success\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-success-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<CheckCircleIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"warning\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-warning-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<WarningDiamondIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\nValidationFeedback.displayName = \"ValidationFeedback\";\n","\"use client\";\n\nimport { EyeIcon } from \"@phosphor-icons/react/Eye\";\nimport { EyeClosedIcon } from \"@phosphor-icons/react/EyeClosed\";\nimport { forwardRef, useEffect, useRef, useState } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { getPrefersReducedMotion } from \"../../hooks/use-prefers-reduced-motion.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport { Input, InputCapture } from \"./input.js\";\nimport type { InputType, WithAutoComplete, WithValidation } from \"./types.js\";\n\ntype PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tWithValidation &\n\tWithAutoComplete & {\n\t\t/**\n\t\t * Callback for when the visibility of the password value changes.\n\t\t */\n\t\tonValueVisibilityChange?: (visible: boolean) => void;\n\t\t/**\n\t\t * Show/hide the password value as a controlled state.\n\t\t * @default false\n\t\t */\n\t\tshowValue?: boolean;\n\t};\n\ntype PasswordInputType = Extract<InputType, \"text\" | \"password\">;\n\n/**\n * A specialized input component for password entry with a toggle button to show/hide the password value.\n * Provides enhanced security UX by allowing users to verify their input while maintaining privacy.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <PasswordInput\n * placeholder=\"Enter your password\"\n * showValue={false}\n * onValueVisibilityChange={(visible) => console.log('Password visible:', visible)}\n * />\n * ```\n */\nconst PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n\t({ onValueVisibilityChange, showValue = false, ...props }, ref) => {\n\t\tconst [showPassword, setShowPassword] = useState<boolean>(showValue);\n\t\tconst type: PasswordInputType = showPassword ? \"text\" : \"password\";\n\t\tconst EyeCon = showPassword ? EyeIcon : EyeClosedIcon;\n\t\tconst iconRef = useRef<SVGSVGElement>(null);\n\t\tconst animationRef = useRef<Animation | null>(null);\n\n\t\tuseEffect(() => {\n\t\t\tsetShowPassword(showValue);\n\t\t}, [showValue]);\n\n\t\treturn (\n\t\t\t<Input type={type} ref={ref} {...props}>\n\t\t\t\t<InputCapture />\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"text-body hover:text-strong ml-1 cursor-pointer bg-inherit p-0\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t// Cancel any in-flight animation so rapid clicks are never blocked\n\t\t\t\t\t\tif (animationRef.current) {\n\t\t\t\t\t\t\tanimationRef.current.cancel();\n\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Flush synchronously so React commits the new icon to the DOM before we animate\n\t\t\t\t\t\tconst nextShowPassword = !showPassword;\n\t\t\t\t\t\tflushSync(() => {\n\t\t\t\t\t\t\tsetShowPassword(nextShowPassword);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tonValueVisibilityChange?.(nextShowPassword);\n\n\t\t\t\t\t\tconst icon = iconRef.current;\n\t\t\t\t\t\tif (icon && !getPrefersReducedMotion()) {\n\t\t\t\t\t\t\tanimationRef.current = icon.animate(\n\t\t\t\t\t\t\t\t[{ transform: \"scaleY(0)\" }, { transform: \"scaleY(1)\" }],\n\t\t\t\t\t\t\t\t{ duration: 200, easing: \"ease-out\" },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tanimationRef.current.onfinish = () => {\n\t\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"sr-only\">Turn password visibility {showPassword ? \"off\" : \"on\"}</span>\n\t\t\t\t\t<Icon ref={iconRef} svg={<EyeCon aria-hidden />} />\n\t\t\t\t</button>\n\t\t\t</Input>\n\t\t);\n\t},\n);\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { PasswordInput };\nexport type { PasswordInputProps };\n"],"mappings":"uvBA2CA,MAAM,EAAQ,GACZ,CAAE,WAAU,YAAW,GAAG,GAAS,IAAiB,CACpD,IAAM,EAAc,EAAQ,EACtB,EAAW,EAA8B,KAAK,CAepD,OAbI,EAEF,EAAC,EAAD,CACY,YACG,eACJ,WACV,GAAI,EAEH,WACe,CAAA,CAKlB,EAAC,EAAD,CACC,GAAI,EACO,YACG,eACJ,oBAEV,EAAC,EAAD,CAAc,GAAI,EAAS,CAAA,CACX,CAAA,EAGnB,CACD,EAAM,YAAc,QAmBpB,MAAM,EAAe,GACnB,CAAE,eAAgB,EAAc,YAAW,WAAY,EAAa,GAAG,GAAa,IAAQ,CAC5F,GAAM,CACL,eAAgB,EAChB,aAAc,EACd,SAAU,EACV,WAAY,EACZ,GAAG,GACA,EAAW,EAAa,CAEtB,EAAa,GAAiB,EAC9B,GACJ,OAAO,GAAe,WAAa,GAAY,CAAG,IAAe,IAAA,GAC7D,EAAc,GAAkB,GAAgB,IAAe,QAC/D,EAAQ,CACb,GAAG,EACH,GAAG,EACH,KAAM,EAAU,MAAQ,EAAI,MAAQ,OACpC,CAED,OACC,EAAC,QAAD,CACC,eAAc,EACd,kBAAiB,EACjB,UAAW,EACV,wJACA,EACA,CACD,IAAK,EAAY,EAAK,EAAiB,EAAY,CACnD,GAAI,EACH,CAAA,EAGJ,CACD,EAAa,YAAc,eAc3B,MAAM,EAAe,EAAgC,CACpD,WAAY,IAAA,GACZ,SAAU,CAAE,QAAS,KAAM,CAC3B,CAAC,CAiBI,GAAkB,CACvB,eAAgB,EAChB,gBAAiB,EACjB,WACA,YACA,WACA,eACA,WACA,QACA,OACA,WAAY,EACZ,GAAG,KACuB,CAE1B,IAAM,EADY,GAAgB,MAAQ,IAAiB,QAExD,QACA,OAAO,GAAgB,WACtB,GAAa,CACb,EACJ,OACC,EAAC,EAAa,SAAd,CACC,MAAO,CACN,eAAgB,EAChB,gBAAiB,EACjB,WACA,OACA,aACA,GAAG,EACH,eACA,WACA,UAED,EAAC,MAAD,CACC,KAAK,OACL,iBAAgB,GAAY,IAAkB,IAAA,GAC9C,kBAAiB,GAAc,IAAA,GAC/B,UAAW,EACV,uCACA,gMACA,2BACA,mHACA,wFACA,6JACA,6JACA,oJACA,sJACA,EACA,CACD,YAAc,GAAU,CAGnB,EAAM,SAAW,GAAU,SAC9B,EAAM,gBAAgB,EAGxB,YAAe,CACd,GAAU,SAAS,OAAO,EAE3B,cAAiB,CACZ,GAAU,UAAY,SAAS,eAClC,GAAU,SAAS,OAAO,EAGrB,iBA/BR,CAiCE,EACD,EAAC,EAAD,CAAoB,KAAM,EAAM,KAAkB,aAAc,CAAA,CAC3D,GACiB,CAAA,EAG1B,EAAe,YAAc,iBAK7B,MAAM,GAAsB,CAC3B,OACA,gBAIK,CACL,OAAQ,EAAR,CACC,IAAK,QACJ,OACC,EAAC,MAAD,CAAK,UAAU,kDAAf,CACC,EAAC,OAAD,CAAM,UAAU,mBACdA,EAAK,4BAA6B,EAAM,+BAA+B,CAClE,CAAA,CACP,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAa,cAAA,GAAY,OAAO,OAAS,CAAA,CAAI,CAAA,CACnD,GAER,IAAK,UACJ,OACC,EAAC,MAAD,CAAK,UAAU,mDACd,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAiB,OAAO,OAAS,CAAA,CAAI,CAAA,CAC3C,CAAA,CAER,IAAK,UACJ,OACC,EAAC,MAAD,CAAK,UAAU,mDACd,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAoB,OAAO,OAAS,CAAA,CAAI,CAAA,CAC9C,CAAA,CAER,QACC,OAAO,OAGV,EAAmB,YAAc,qBClOjC,MAAM,EAAgB,GACpB,CAAE,0BAAyB,YAAY,GAAO,GAAG,GAAS,IAAQ,CAClE,GAAM,CAAC,EAAc,GAAmB,EAAkB,EAAU,CAC9D,EAA0B,EAAe,OAAS,WAClD,EAAS,EAAe,EAAU,EAClC,EAAU,EAAsB,KAAK,CACrC,EAAe,EAAyB,KAAK,CAMnD,OAJA,MAAgB,CACf,EAAgB,EAAU,EACxB,CAAC,EAAU,CAAC,CAGd,EAAC,EAAD,CAAa,OAAW,MAAK,GAAI,WAAjC,CACC,EAAC,EAAD,EAAgB,CAAA,CAChB,EAAC,SAAD,CACC,KAAK,SACL,SAAU,GACV,UAAU,iEACV,YAAe,CAEd,AAEC,EAAa,WADb,EAAa,QAAQ,QAAQ,CACN,MAIxB,IAAM,EAAmB,CAAC,EAC1B,MAAgB,CACf,EAAgB,EAAiB,EAChC,CACF,IAA0B,EAAiB,CAE3C,IAAM,EAAO,EAAQ,QACjB,GAAQ,CAAC,GAAyB,GACrC,EAAa,QAAU,EAAK,QAC3B,CAAC,CAAE,UAAW,YAAa,CAAE,CAAE,UAAW,YAAa,CAAC,CACxD,CAAE,SAAU,IAAK,OAAQ,WAAY,CACrC,CACD,EAAa,QAAQ,aAAiB,CACrC,EAAa,QAAU,iBAzB3B,CA8BC,EAAC,OAAD,CAAM,UAAU,mBAAhB,CAA0B,4BAA0B,EAAe,MAAQ,KAAY,GACvF,EAAC,EAAD,CAAM,IAAK,EAAS,IAAK,EAAC,EAAD,CAAQ,cAAA,GAAc,CAAA,CAAI,CAAA,CAC3C,GACF,IAGV,CACD,EAAc,YAAc"}
|
|
1
|
+
{"version":3,"file":"input.js","names":["clsx"],"sources":["../src/components/input/input.tsx","../src/components/input/password-input.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckCircleIcon } from \"@phosphor-icons/react/CheckCircle\";\nimport { WarningIcon } from \"@phosphor-icons/react/Warning\";\nimport { WarningDiamondIcon } from \"@phosphor-icons/react/WarningDiamond\";\nimport clsx from \"clsx\";\nimport type {\n\tComponentRef,\n\tForwardedRef,\n\tInputHTMLAttributes,\n\tMutableRefObject,\n\tPropsWithChildren,\n} from \"react\";\nimport { createContext, forwardRef, useContext, useRef } from \"react\";\nimport { composeRefs } from \"../../utils/compose-refs/compose-refs.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport type { Validation, WithAutoComplete, WithInputType, WithValidation } from \"./types.js\";\n\ntype BaseProps = WithAutoComplete & WithInputType & WithValidation;\n\n/**\n * The props for the `Input` component.\n */\ntype InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps &\n\tPropsWithChildren;\n\n/**\n * Used to create interactive controls for web-based forms in order to accept data from the user.\n * A versatile input element that supports various types, validation states, and can be composed with other elements.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * validation=\"success\"\n * />\n * ```\n */\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n\t({ children, className, ...props }, forwardedRef) => {\n\t\tconst hasChildren = Boolean(children);\n\t\tconst innerRef = useRef<ComponentRef<\"input\">>(null);\n\n\t\tif (hasChildren) {\n\t\t\treturn (\n\t\t\t\t<InputContainer\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\t\tinnerRef={innerRef}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</InputContainer>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<InputContainer\n\t\t\t\t{...props}\n\t\t\t\tclassName={className}\n\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\tinnerRef={innerRef}\n\t\t\t>\n\t\t\t\t<InputCapture {...props} />\n\t\t\t</InputContainer>\n\t\t);\n\t},\n);\nInput.displayName = \"Input\";\n\ntype InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps;\n\n/**\n * The actual <input /> element that captures user input.\n * Used internally by Input component or when you need direct control over the input element.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input>\n * <InputCapture />\n * <Icon svg={<SearchIcon />} />\n * </Input>\n * ```\n */\nconst InputCapture = forwardRef<HTMLInputElement, InputCaptureProps>(\n\t({ \"aria-invalid\": _ariaInvalid, className, validation: _validation, ...restProps }, ref) => {\n\t\tconst {\n\t\t\t\"aria-invalid\": ctxAriaInvalid,\n\t\t\tforwardedRef: ctxForwardedRef,\n\t\t\tinnerRef: ctxInnerRef,\n\t\t\tvalidation: ctxValidation,\n\t\t\t...ctx\n\t\t} = useContext(InputContext);\n\n\t\tconst validation = ctxValidation ?? _validation;\n\t\tconst validationValue =\n\t\t\t(typeof validation === \"function\" ? validation() : validation) || undefined;\n\t\tconst ariaInvalid = ctxAriaInvalid ?? _ariaInvalid ?? validation === \"error\";\n\t\tconst props = {\n\t\t\t...ctx,\n\t\t\t...restProps,\n\t\t\ttype: restProps.type ?? ctx.type ?? \"text\",\n\t\t};\n\n\t\treturn (\n\t\t\t<input\n\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\tdata-slot=\"input-capture\"\n\t\t\t\tdata-validation={validationValue}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"placeholder:text-placeholder min-w-0 flex-1 bg-transparent text-left autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] focus:outline-hidden\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={composeRefs(ref, ctxForwardedRef, ctxInnerRef)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputCapture.displayName = \"InputCapture\";\n\ntype InputContextType = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps & {\n\t\t/**\n\t\t * inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * forwarded ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef?: ForwardedRef<HTMLInputElement>;\n\t};\n\nconst InputContext = createContext<InputContextType>({\n\tvalidation: undefined,\n\tinnerRef: { current: null },\n});\n\ntype InputContainerProps = InputHTMLAttributes<HTMLInputElement> &\n\tBaseProps & {\n\t\t/**\n\t\t * @private inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * @private ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef: ForwardedRef<HTMLInputElement>;\n\t};\n\n/**\n * The container for the input element.\n */\nconst InputContainer = ({\n\t\"aria-invalid\": _ariaInvalid,\n\t\"aria-disabled\": _ariaDisabled,\n\t\"data-slot\": dataSlot = \"input\",\n\tchildren,\n\tclassName,\n\tdisabled,\n\tforwardedRef,\n\tinnerRef,\n\tstyle,\n\ttype,\n\tvalidation: _validation,\n\t...props\n}: InputContainerProps & { \"data-slot\"?: string }) => {\n\tconst isInvalid = _ariaInvalid != null && _ariaInvalid !== \"false\";\n\tconst validation = isInvalid\n\t\t? \"error\"\n\t\t: typeof _validation === \"function\"\n\t\t\t? _validation()\n\t\t\t: _validation;\n\treturn (\n\t\t<InputContext.Provider\n\t\t\tvalue={{\n\t\t\t\t\"aria-invalid\": _ariaInvalid,\n\t\t\t\t\"aria-disabled\": _ariaDisabled,\n\t\t\t\tdisabled,\n\t\t\t\ttype,\n\t\t\t\tvalidation,\n\t\t\t\t...props,\n\t\t\t\tforwardedRef,\n\t\t\t\tinnerRef,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\trole=\"none\"\n\t\t\t\tdata-slot={dataSlot}\n\t\t\t\tdata-disabled={(disabled ?? _ariaDisabled) || undefined}\n\t\t\t\tdata-validation={validation || undefined}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"pointer-coarse:text-base h-9 text-sm\",\n\t\t\t\t\t\"bg-form relative flex w-full items-center gap-1.5 rounded-md border px-3 py-2 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-within:outline-hidden focus-within:ring-4\",\n\t\t\t\t\t\"data-disabled:opacity-50\",\n\t\t\t\t\t\"has-[input:not(:first-child)]:ps-2.5 has-[input:not(:last-child)]:pe-2.5 [&>:not(input)]:shrink-0 [&_svg]:size-5\",\n\t\t\t\t\t\"border-form text-strong focus-within:border-accent-600 focus-within:ring-focus-accent\",\n\t\t\t\t\t\"data-validation-success:border-success-600 focus-within:data-validation-success:border-success-600 focus-within:data-validation-success:ring-focus-success\",\n\t\t\t\t\t\"data-validation-warning:border-warning-600 focus-within:data-validation-warning:border-warning-600 focus-within:data-validation-warning:ring-focus-warning\",\n\t\t\t\t\t\"data-validation-error:border-danger-600 focus-within:data-validation-error:border-danger-600 focus-within:data-validation-error:ring-focus-danger\",\n\t\t\t\t\t\"autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] has-autofill:bg-blue-50 has-autofill:[-webkit-text-fill-color:var(--text-color-strong)]\", // Autofill styling on the input itself and any children with autofill styling\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t// Prevent mousedown on non-input children (icons, buttons, etc.) from\n\t\t\t\t\t// blurring the input, which would cause the focus ring to flicker.\n\t\t\t\t\tif (event.target !== innerRef?.current) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t}}\n\t\t\t\tonKeyDown={() => {\n\t\t\t\t\tif (innerRef?.current !== document.activeElement) {\n\t\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<ValidationFeedback name={props.name} validation={validation} />\n\t\t\t</div>\n\t\t</InputContext.Provider>\n\t);\n};\nInputContainer.displayName = \"InputContainer\";\n\nexport { Input, InputCapture };\nexport type { InputProps, InputCaptureProps };\n\nconst ValidationFeedback = ({\n\tname,\n\tvalidation,\n}: {\n\tname?: string;\n\tvalidation: Validation | undefined;\n}) => {\n\tswitch (validation) {\n\t\tcase \"error\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-danger-600 order-last select-none\">\n\t\t\t\t\t<span className=\"sr-only\">\n\t\t\t\t\t\t{clsx(\"The value entered for the\", name, \"input has failed validation.\")}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Icon svg={<WarningIcon aria-hidden weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"success\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-success-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<CheckCircleIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"warning\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-warning-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<WarningDiamondIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\nValidationFeedback.displayName = \"ValidationFeedback\";\n","\"use client\";\n\nimport { EyeIcon } from \"@phosphor-icons/react/Eye\";\nimport { EyeClosedIcon } from \"@phosphor-icons/react/EyeClosed\";\nimport { forwardRef, useEffect, useRef, useState } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { getPrefersReducedMotion } from \"../../hooks/use-prefers-reduced-motion.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport { Input, InputCapture } from \"./input.js\";\nimport type { InputType, WithAutoComplete, WithValidation } from \"./types.js\";\n\ntype PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tWithValidation &\n\tWithAutoComplete & {\n\t\t/**\n\t\t * Callback for when the visibility of the password value changes.\n\t\t */\n\t\tonValueVisibilityChange?: (visible: boolean) => void;\n\t\t/**\n\t\t * Show/hide the password value as a controlled state.\n\t\t * @default false\n\t\t */\n\t\tshowValue?: boolean;\n\t};\n\ntype PasswordInputType = Extract<InputType, \"text\" | \"password\">;\n\n/**\n * A specialized input component for password entry with a toggle button to show/hide the password value.\n * Provides enhanced security UX by allowing users to verify their input while maintaining privacy.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <PasswordInput\n * placeholder=\"Enter your password\"\n * showValue={false}\n * onValueVisibilityChange={(visible) => console.log('Password visible:', visible)}\n * />\n * ```\n */\nconst PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n\t({ onValueVisibilityChange, showValue = false, ...props }, ref) => {\n\t\tconst [showPassword, setShowPassword] = useState<boolean>(showValue);\n\t\tconst type: PasswordInputType = showPassword ? \"text\" : \"password\";\n\t\tconst EyeCon = showPassword ? EyeIcon : EyeClosedIcon;\n\t\tconst iconRef = useRef<SVGSVGElement>(null);\n\t\tconst animationRef = useRef<Animation | null>(null);\n\n\t\tuseEffect(() => {\n\t\t\tsetShowPassword(showValue);\n\t\t}, [showValue]);\n\n\t\treturn (\n\t\t\t<Input data-slot=\"password-input\" type={type} ref={ref} {...props}>\n\t\t\t\t<InputCapture />\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"text-body hover:text-strong ml-1 cursor-pointer bg-inherit p-0\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t// Cancel any in-flight animation so rapid clicks are never blocked\n\t\t\t\t\t\tif (animationRef.current) {\n\t\t\t\t\t\t\tanimationRef.current.cancel();\n\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Flush synchronously so React commits the new icon to the DOM before we animate\n\t\t\t\t\t\tconst nextShowPassword = !showPassword;\n\t\t\t\t\t\tflushSync(() => {\n\t\t\t\t\t\t\tsetShowPassword(nextShowPassword);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tonValueVisibilityChange?.(nextShowPassword);\n\n\t\t\t\t\t\tconst icon = iconRef.current;\n\t\t\t\t\t\tif (icon && !getPrefersReducedMotion()) {\n\t\t\t\t\t\t\tanimationRef.current = icon.animate(\n\t\t\t\t\t\t\t\t[{ transform: \"scaleY(0)\" }, { transform: \"scaleY(1)\" }],\n\t\t\t\t\t\t\t\t{ duration: 200, easing: \"ease-out\" },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tanimationRef.current.onfinish = () => {\n\t\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"sr-only\">Turn password visibility {showPassword ? \"off\" : \"on\"}</span>\n\t\t\t\t\t<Icon ref={iconRef} svg={<EyeCon aria-hidden />} />\n\t\t\t\t</button>\n\t\t\t</Input>\n\t\t);\n\t},\n);\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { PasswordInput };\nexport type { PasswordInputProps };\n"],"mappings":"uvBA2CA,MAAM,EAAQ,GACZ,CAAE,WAAU,YAAW,GAAG,GAAS,IAAiB,CACpD,IAAM,EAAc,EAAQ,EACtB,EAAW,EAA8B,KAAK,CAepD,OAbI,EAEF,EAAC,EAAD,CACY,YACG,eACJ,WACV,GAAI,EAEH,WACe,CAAA,CAKlB,EAAC,EAAD,CACC,GAAI,EACO,YACG,eACJ,oBAEV,EAAC,EAAD,CAAc,GAAI,EAAS,CAAA,CACX,CAAA,EAGnB,CACD,EAAM,YAAc,QAmBpB,MAAM,EAAe,GACnB,CAAE,eAAgB,EAAc,YAAW,WAAY,EAAa,GAAG,GAAa,IAAQ,CAC5F,GAAM,CACL,eAAgB,EAChB,aAAc,EACd,SAAU,EACV,WAAY,EACZ,GAAG,GACA,EAAW,EAAa,CAEtB,EAAa,GAAiB,EAC9B,GACJ,OAAO,GAAe,WAAa,GAAY,CAAG,IAAe,IAAA,GAC7D,EAAc,GAAkB,GAAgB,IAAe,QAC/D,EAAQ,CACb,GAAG,EACH,GAAG,EACH,KAAM,EAAU,MAAQ,EAAI,MAAQ,OACpC,CAED,OACC,EAAC,QAAD,CACC,eAAc,EACd,YAAU,gBACV,kBAAiB,EACjB,UAAW,EACV,wJACA,EACA,CACD,IAAK,EAAY,EAAK,EAAiB,EAAY,CACnD,GAAI,EACH,CAAA,EAGJ,CACD,EAAa,YAAc,eAc3B,MAAM,EAAe,EAAgC,CACpD,WAAY,IAAA,GACZ,SAAU,CAAE,QAAS,KAAM,CAC3B,CAAC,CAiBI,GAAkB,CACvB,eAAgB,EAChB,gBAAiB,EACjB,YAAa,EAAW,QACxB,WACA,YACA,WACA,eACA,WACA,QACA,OACA,WAAY,EACZ,GAAG,KACkD,CAErD,IAAM,EADY,GAAgB,MAAQ,IAAiB,QAExD,QACA,OAAO,GAAgB,WACtB,GAAa,CACb,EACJ,OACC,EAAC,EAAa,SAAd,CACC,MAAO,CACN,eAAgB,EAChB,gBAAiB,EACjB,WACA,OACA,aACA,GAAG,EACH,eACA,WACA,UAED,EAAC,MAAD,CACC,KAAK,OACL,YAAW,EACX,iBAAgB,GAAY,IAAkB,IAAA,GAC9C,kBAAiB,GAAc,IAAA,GAC/B,UAAW,EACV,uCACA,gMACA,2BACA,mHACA,wFACA,6JACA,6JACA,oJACA,sJACA,EACA,CACD,YAAc,GAAU,CAGnB,EAAM,SAAW,GAAU,SAC9B,EAAM,gBAAgB,EAGxB,YAAe,CACd,GAAU,SAAS,OAAO,EAE3B,cAAiB,CACZ,GAAU,UAAY,SAAS,eAClC,GAAU,SAAS,OAAO,EAGrB,iBAhCR,CAkCE,EACD,EAAC,EAAD,CAAoB,KAAM,EAAM,KAAkB,aAAc,CAAA,CAC3D,GACiB,CAAA,EAG1B,EAAe,YAAc,iBAK7B,MAAM,GAAsB,CAC3B,OACA,gBAIK,CACL,OAAQ,EAAR,CACC,IAAK,QACJ,OACC,EAAC,MAAD,CAAK,UAAU,kDAAf,CACC,EAAC,OAAD,CAAM,UAAU,mBACdA,EAAK,4BAA6B,EAAM,+BAA+B,CAClE,CAAA,CACP,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAa,cAAA,GAAY,OAAO,OAAS,CAAA,CAAI,CAAA,CACnD,GAER,IAAK,UACJ,OACC,EAAC,MAAD,CAAK,UAAU,mDACd,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAiB,OAAO,OAAS,CAAA,CAAI,CAAA,CAC3C,CAAA,CAER,IAAK,UACJ,OACC,EAAC,MAAD,CAAK,UAAU,mDACd,EAAC,EAAD,CAAM,IAAK,EAAC,EAAD,CAAoB,OAAO,OAAS,CAAA,CAAI,CAAA,CAC9C,CAAA,CAER,QACC,OAAO,OAGV,EAAmB,YAAc,qBCrOjC,MAAM,EAAgB,GACpB,CAAE,0BAAyB,YAAY,GAAO,GAAG,GAAS,IAAQ,CAClE,GAAM,CAAC,EAAc,GAAmB,EAAkB,EAAU,CAC9D,EAA0B,EAAe,OAAS,WAClD,EAAS,EAAe,EAAU,EAClC,EAAU,EAAsB,KAAK,CACrC,EAAe,EAAyB,KAAK,CAMnD,OAJA,MAAgB,CACf,EAAgB,EAAU,EACxB,CAAC,EAAU,CAAC,CAGd,EAAC,EAAD,CAAO,YAAU,iBAAuB,OAAW,MAAK,GAAI,WAA5D,CACC,EAAC,EAAD,EAAgB,CAAA,CAChB,EAAC,SAAD,CACC,KAAK,SACL,SAAU,GACV,UAAU,iEACV,YAAe,CAEd,AAEC,EAAa,WADb,EAAa,QAAQ,QAAQ,CACN,MAIxB,IAAM,EAAmB,CAAC,EAC1B,MAAgB,CACf,EAAgB,EAAiB,EAChC,CACF,IAA0B,EAAiB,CAE3C,IAAM,EAAO,EAAQ,QACjB,GAAQ,CAAC,GAAyB,GACrC,EAAa,QAAU,EAAK,QAC3B,CAAC,CAAE,UAAW,YAAa,CAAE,CAAE,UAAW,YAAa,CAAC,CACxD,CAAE,SAAU,IAAK,OAAQ,WAAY,CACrC,CACD,EAAa,QAAQ,aAAiB,CACrC,EAAa,QAAU,iBAzB3B,CA8BC,EAAC,OAAD,CAAM,UAAU,mBAAhB,CAA0B,4BAA0B,EAAe,MAAQ,KAAY,GACvF,EAAC,EAAD,CAAM,IAAK,EAAS,IAAK,EAAC,EAAD,CAAQ,cAAA,GAAc,CAAA,CAAI,CAAA,CAC3C,GACF,IAGV,CACD,EAAc,YAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{jsx as t}from"react/jsx-runtime";function n({children:n,className:r,...i}){return t(`kbd`,{"data-slot":`kbd`,className:e(`[font-kerning:normal] [font-variant-ligatures:common-ligatures_contextual]`,`appearance-none tabular-nums inline-grid place-items-center size-5 bg-neutral-500/15 px-1 rounded text-mono leading-none font-mono`,r),...i,children:n})}export{n as t};
|
|
2
|
+
//# sourceMappingURL=kbd-B0wWeV_0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kbd-
|
|
1
|
+
{"version":3,"file":"kbd-B0wWeV_0.js","names":[],"sources":["../src/components/kbd/kbd.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A square, centered keyboard “key” chip for rendering shortcut hints\n * (e.g., \"K\", \"⌘\", \"⌃\"). Designed so every key—letters and modifiers—shares\n * the same visual height/width and baseline. Renders a native `<kbd>` element.\n *\n * Accessibility:\n * - When showing a symbol (⌘/⌃), provide an accessible name via `aria-label`\n * or include an sr-only label inside. The visible glyph may be marked\n * `aria-hidden`.\n *\n * @example Basic letter key\n * <Kbd>K</Kbd>\n */\nfunction Kbd({ children, className, ...props }: ComponentProps<\"kbd\">) {\n\treturn (\n\t\t<kbd\n\t\t\tdata-slot=\"kbd\"\n\t\t\tclassName={cx(\n\t\t\t\t\"[font-kerning:normal] [font-variant-ligatures:common-ligatures_contextual]\",\n\t\t\t\t\"appearance-none tabular-nums inline-grid place-items-center size-5 bg-neutral-500/15 px-1 rounded text-mono leading-none font-mono\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</kbd>\n\t);\n}\n\nexport {\n\t//,\n\tKbd,\n};\n"],"mappings":"6EAgBA,SAAS,EAAI,CAAE,WAAU,YAAW,GAAG,GAAgC,CACtE,OACC,EAAC,MAAD,CACC,YAAU,MACV,UAAW,EACV,6EACA,qIACA,EACA,CACD,GAAI,EAEH,WACI,CAAA"}
|
package/dist/kbd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./kbd-
|
|
1
|
+
import{t as e}from"./kbd-B0wWeV_0.js";export{e as Kbd};
|
package/dist/label.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{forwardRef as t}from"react";import{jsx as n}from"react/jsx-runtime";const r=t(({"aria-disabled":t,children:r,className:i,disabled:a,onMouseDown:o,...s},c)=>n(`label`,{"aria-disabled":a??t,className:e(`text-strong cursor-pointer text-sm peer-disabled:cursor-default has-disabled:cursor-default aria-disabled:cursor-default font-sans`,i),onMouseDown:e=>{e.target.closest(`button, input, select, textarea`)||(o?.(e),!e.defaultPrevented&&e.detail>1&&e.preventDefault())},ref:c,...s,children:r}));r.displayName=`Label`;export{r as Label};
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{forwardRef as t}from"react";import{jsx as n}from"react/jsx-runtime";const r=t(({"aria-disabled":t,children:r,className:i,disabled:a,onMouseDown:o,...s},c)=>n(`label`,{"aria-disabled":a??t,"data-slot":`label`,className:e(`text-strong cursor-pointer text-sm peer-disabled:cursor-default has-disabled:cursor-default aria-disabled:cursor-default font-sans`,i),onMouseDown:e=>{e.target.closest(`button, input, select, textarea`)||(o?.(e),!e.defaultPrevented&&e.detail>1&&e.preventDefault())},ref:c,...s,children:r}));r.displayName=`Label`;export{r as Label};
|
|
2
2
|
//# sourceMappingURL=label.js.map
|
package/dist/label.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.js","names":[],"sources":["../src/components/label/label.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ComponentRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\ntype LabelProps = ComponentPropsWithoutRef<\"label\"> & {\n\t/**\n\t * If set, the label will appear disabled.\n\t */\n\tdisabled?: boolean;\n};\n\n/**\n * A Label represents a caption for an item in a user interface. It is used to\n * provide a description or title for a form control, such as an input field,\n * checkbox, radio button, etc. The label is typically displayed next to the\n * form control and helps users understand its purpose.\n *\n * @see https://mantle.ngrok.com/components/label\n *\n * @example\n * ```tsx\n * <Label htmlFor=\"name\">\n * Name: <Input type=\"text\" id=\"name\" />\n * </Label>\n *\n * <div className=\"flex items-center gap-2\">\n * <Label htmlFor=\"name-2\">Name:</Label>\n * <Input type=\"text\" id=\"name-2\" />\n * </div>\n * ```\n */\nconst Label = forwardRef<ComponentRef<\"label\">, LabelProps>(\n\t(\n\t\t{ \"aria-disabled\": _ariaDisabled, children, className, disabled, onMouseDown, ...props },\n\t\tref,\n\t) => (\n\t\t// biome-ignore lint/a11y/noLabelWithoutControl: this is a composable label component\n\t\t<label\n\t\t\taria-disabled={disabled ?? _ariaDisabled}\n\t\t\tclassName={cx(\n\t\t\t\t\"text-strong cursor-pointer text-sm peer-disabled:cursor-default has-disabled:cursor-default aria-disabled:cursor-default font-sans\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonMouseDown={(event) => {\n\t\t\t\t// only prevent text selection if clicking inside the label itself\n\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\tif (target.closest(\"button, input, select, textarea\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tonMouseDown?.(event);\n\n\t\t\t\t// prevent text selection when double clicking label\n\t\t\t\tif (!event.defaultPrevented && event.detail > 1) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}}\n\t\t\tref={ref}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</label>\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport {\n\t//\n\tLabel,\n};\n"],"mappings":"gHA+BA,MAAM,EAAQ,GAEZ,CAAE,gBAAiB,EAAe,WAAU,YAAW,WAAU,cAAa,GAAG,GACjF,IAGA,EAAC,QAAD,CACC,gBAAe,GAAY,EAC3B,UAAW,EACV,qIACA,EACA,CACD,YAAc,GAAU,CAER,EAAM,OACV,QAAQ,kCAAkC,GAIrD,IAAc,EAAM,CAGhB,CAAC,EAAM,kBAAoB,EAAM,OAAS,GAC7C,EAAM,gBAAgB,GAGnB,MACL,GAAI,EAEH,WACM,CAAA,CAET,CACD,EAAM,YAAc"}
|
|
1
|
+
{"version":3,"file":"label.js","names":[],"sources":["../src/components/label/label.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ComponentRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\ntype LabelProps = ComponentPropsWithoutRef<\"label\"> & {\n\t/**\n\t * If set, the label will appear disabled.\n\t */\n\tdisabled?: boolean;\n};\n\n/**\n * A Label represents a caption for an item in a user interface. It is used to\n * provide a description or title for a form control, such as an input field,\n * checkbox, radio button, etc. The label is typically displayed next to the\n * form control and helps users understand its purpose.\n *\n * @see https://mantle.ngrok.com/components/label\n *\n * @example\n * ```tsx\n * <Label htmlFor=\"name\">\n * Name: <Input type=\"text\" id=\"name\" />\n * </Label>\n *\n * <div className=\"flex items-center gap-2\">\n * <Label htmlFor=\"name-2\">Name:</Label>\n * <Input type=\"text\" id=\"name-2\" />\n * </div>\n * ```\n */\nconst Label = forwardRef<ComponentRef<\"label\">, LabelProps>(\n\t(\n\t\t{ \"aria-disabled\": _ariaDisabled, children, className, disabled, onMouseDown, ...props },\n\t\tref,\n\t) => (\n\t\t// biome-ignore lint/a11y/noLabelWithoutControl: this is a composable label component\n\t\t<label\n\t\t\taria-disabled={disabled ?? _ariaDisabled}\n\t\t\tdata-slot=\"label\"\n\t\t\tclassName={cx(\n\t\t\t\t\"text-strong cursor-pointer text-sm peer-disabled:cursor-default has-disabled:cursor-default aria-disabled:cursor-default font-sans\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonMouseDown={(event) => {\n\t\t\t\t// only prevent text selection if clicking inside the label itself\n\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\tif (target.closest(\"button, input, select, textarea\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tonMouseDown?.(event);\n\n\t\t\t\t// prevent text selection when double clicking label\n\t\t\t\tif (!event.defaultPrevented && event.detail > 1) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}}\n\t\t\tref={ref}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</label>\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport {\n\t//\n\tLabel,\n};\n"],"mappings":"gHA+BA,MAAM,EAAQ,GAEZ,CAAE,gBAAiB,EAAe,WAAU,YAAW,WAAU,cAAa,GAAG,GACjF,IAGA,EAAC,QAAD,CACC,gBAAe,GAAY,EAC3B,YAAU,QACV,UAAW,EACV,qIACA,EACA,CACD,YAAc,GAAU,CAER,EAAM,OACV,QAAQ,kCAAkC,GAIrD,IAAc,EAAM,CAGhB,CAAC,EAAM,kBAAoB,EAAM,OAAS,GAC7C,EAAM,gBAAgB,GAGnB,MACL,GAAI,EAEH,WACM,CAAA,CAET,CACD,EAAM,YAAc"}
|
package/dist/main.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{jsx as t}from"react/jsx-runtime";const n=({className:n,...r})=>t(`main`,{...r,id:`main`,tabIndex:-1,className:e(`focus:outline-hidden`,n)});n.displayName=`Main`;export{n as Main};
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{jsx as t}from"react/jsx-runtime";const n=({className:n,...r})=>t(`main`,{...r,"data-slot":`main`,id:`main`,tabIndex:-1,className:e(`focus:outline-hidden`,n)});n.displayName=`Main`;export{n as Main};
|
|
2
2
|
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":[],"sources":["../src/components/main/main.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A focusable `<main>` landmark for the page's primary content. Renders with\n * `id=\"main\"` and `tabIndex={-1}` so a skip link (or any programmatic focus\n * call) can send keyboard users directly to the main content without exposing\n * a visible focus ring on the region itself (`focus:outline-hidden`).\n *\n * Pair with the `<SkipToMainLink>` component at the top of the document.\n *\n * @see https://mantle.ngrok.com/components/main\n *\n * @example\n * ```tsx\n * <SkipToMainLink />\n * <Header />\n * <Main>\n * <h1>Page title</h1>\n * </Main>\n * ```\n */\nconst Main = ({ className, ...props }: ComponentProps<\"main\">) => {\n\treturn (\n\t\t<main
|
|
1
|
+
{"version":3,"file":"main.js","names":[],"sources":["../src/components/main/main.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A focusable `<main>` landmark for the page's primary content. Renders with\n * `id=\"main\"` and `tabIndex={-1}` so a skip link (or any programmatic focus\n * call) can send keyboard users directly to the main content without exposing\n * a visible focus ring on the region itself (`focus:outline-hidden`).\n *\n * Pair with the `<SkipToMainLink>` component at the top of the document.\n *\n * @see https://mantle.ngrok.com/components/main\n *\n * @example\n * ```tsx\n * <SkipToMainLink />\n * <Header />\n * <Main>\n * <h1>Page title</h1>\n * </Main>\n * ```\n */\nconst Main = ({ className, ...props }: ComponentProps<\"main\">) => {\n\treturn (\n\t\t<main\n\t\t\t{...props}\n\t\t\tdata-slot=\"main\"\n\t\t\tid=\"main\"\n\t\t\ttabIndex={-1}\n\t\t\tclassName={cx(\"focus:outline-hidden\", className)}\n\t\t/>\n\t);\n};\nMain.displayName = \"Main\";\n\nexport {\n\t//,\n\tMain,\n};\n"],"mappings":"6EAsBA,MAAM,GAAQ,CAAE,YAAW,GAAG,KAE5B,EAAC,OAAD,CACC,GAAI,EACJ,YAAU,OACV,GAAG,OACH,SAAU,GACV,UAAW,EAAG,uBAAwB,EAAU,CAC/C,CAAA,CAGJ,EAAK,YAAc"}
|
package/dist/media-object.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./slot-D_ZUrdEW.js";import{forwardRef as n}from"react";import{jsx as r}from"react/jsx-runtime";const i=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,className:e(`flex gap-4`,i),style:o,children:a}));i.displayName=`MediaObject`;const a=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,className:e(`shrink-0 leading-none`,i),style:o,children:a}));a.displayName=`MediaObjectMedia`;const o=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,className:e(`min-w-0 flex-1`,i),style:o,children:a}));o.displayName=`MediaObject.Content`;const s={Root:i,Media:a,Content:o};export{s as MediaObject};
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./slot-D_ZUrdEW.js";import{forwardRef as n}from"react";import{jsx as r}from"react/jsx-runtime";const i=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,"data-slot":`media-object`,className:e(`flex gap-4`,i),style:o,children:a}));i.displayName=`MediaObject`;const a=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,"data-slot":`media-object-media`,className:e(`shrink-0 leading-none`,i),style:o,children:a}));a.displayName=`MediaObjectMedia`;const o=n(({asChild:n=!1,className:i,children:a,style:o},s)=>r(n?t:`div`,{ref:s,"data-slot":`media-object-content`,className:e(`min-w-0 flex-1`,i),style:o,children:a}));o.displayName=`MediaObject.Content`;const s={Root:i,Media:a,Content:o};export{s as MediaObject};
|
|
2
2
|
//# sourceMappingURL=media-object.js.map
|
package/dist/media-object.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-object.js","names":[],"sources":["../src/components/media-object/media-object.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype Props = ComponentProps<\"div\"> & WithAsChild;\n\n/**\n * The media object is an image/icon (media) to the left, with descriptive\n * content (title and subtitle/description) to the right. This is the root\n * component of the media object.\n */\nconst Root = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component
|
|
1
|
+
{"version":3,"file":"media-object.js","names":[],"sources":["../src/components/media-object/media-object.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype Props = ComponentProps<\"div\"> & WithAsChild;\n\n/**\n * The media object is an image/icon (media) to the left, with descriptive\n * content (title and subtitle/description) to the right. This is the root\n * component of the media object.\n */\nconst Root = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object\"\n\t\t\t\tclassName={cx(\"flex gap-4\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nRoot.displayName = \"MediaObject\";\n\n/**\n * The container for an image or icon to display in the media slot of the media object.\n */\nconst Media = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object-media\"\n\t\t\t\tclassName={cx(\"shrink-0 leading-none\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nMedia.displayName = \"MediaObjectMedia\";\n\n/**\n * The container for the content slot of a media object.\n */\nconst Content = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object-content\"\n\t\t\t\tclassName={cx(\"min-w-0 flex-1\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nContent.displayName = \"MediaObject.Content\";\n\n/**\n * The media object is an image/icon (media) to the left, with descriptive\n * content (title and subtitle/description) to the right. This is the root\n * component of the media object.\n *\n * Change the spacing between the media and content by passing a `gap-*` class.\n * The default gap is `gap-4`.\n *\n * Use flexbox utilities to change the alignment of the media and content.\n *\n * Compose the media object with the `MediaObject.Media` and `MediaObject.Content`\n * components as direct children.\n *\n * @see https://mantle.ngrok.com/components/media-object\n *\n * @example\n * Composition:\n * ```\n * MediaObject.Root\n * ├── MediaObject.Media\n * └── MediaObject.Content\n * ```\n *\n * @example\n * ```tsx\n * <MediaObject.Root>\n * <MediaObject.Media>\n * <ExampleMedia />\n * </MediaObject.Media>\n * <MediaObject.Content>\n * <p>Ea culpa id id ea minim labore.</p>\n * </MediaObject.Content>\n * </MediaObject.Root>\n * ```\n */\nconst MediaObject = {\n\t/**\n\t * The media object is an image/icon (media) to the left, with descriptive\n\t * content (title and subtitle/description) to the right. This is the root\n\t * component of the media object.\n\t *\n\t * Change the spacing between the media and content by passing a `gap-*` class.\n\t * The default gap is `gap-4`.\n\t *\n\t * Use flexbox utilities to change the alignment of the media and content.\n\t *\n\t * Compose the media object with the `MediaObject.Media` and `MediaObject.Content`\n\t * components as direct children.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * The container for an image or icon to display in the media slot of the media object.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectmedia\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tMedia,\n\t/**\n\t * The container for the content slot of a media object.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectcontent\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tContent,\n} as const;\n\nexport {\n\t//,\n\tMediaObject,\n};\n"],"mappings":"kJAaA,MAAM,EAAO,GACX,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,eACV,UAAW,EAAG,aAAc,EAAU,CAC/B,QAEN,WACU,CAAA,CAGd,CACD,EAAK,YAAc,cAKnB,MAAM,EAAQ,GACZ,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,qBACV,UAAW,EAAG,wBAAyB,EAAU,CAC1C,QAEN,WACU,CAAA,CAGd,CACD,EAAM,YAAc,mBAKpB,MAAM,EAAU,GACd,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,uBACV,UAAW,EAAG,iBAAkB,EAAU,CACnC,QAEN,WACU,CAAA,CAGd,CACD,EAAQ,YAAc,sBAqCtB,MAAM,EAAc,CA4BnB,OAkBA,QAkBA,UACA"}
|
package/dist/multi-select.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-BMH0fD_b.js";import{t as n}from"./slot-D_ZUrdEW.js";import{t as r}from"./compose-refs-DFIaEnQH.js";import{n as i}from"./separator-Yk9hMn8E.js";import{t as a}from"./use-prefers-reduced-motion-BcwST13S.js";import{createContext as o,forwardRef as s,useCallback as c,useContext as l,useEffect as u,useMemo as d,useRef as f}from"react";import{Fragment as p,jsx as m,jsxs as h}from"react/jsx-runtime";import{XIcon as g}from"@phosphor-icons/react/X";import{CheckIcon as _}from"@phosphor-icons/react/Check";import*as v from"@ariakit/react";import{LockIcon as y}from"@phosphor-icons/react/Lock";const b=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`),x=[],S=o({current:null}),C=o({current:[]}),w=o({onInputKeyDownRef:{current:void 0},inputRef:{current:null}}),T=({children:e,defaultSelectedValue:t=[],...n})=>{let r=f(null),i=f(void 0),a=f(null),o=f([]),s=d(()=>({onInputKeyDownRef:i,inputRef:a}),[]);return m(S.Provider,{value:r,children:m(w.Provider,{value:s,children:m(C.Provider,{value:o,children:m(v.ComboboxProvider,{defaultSelectedValue:t,...n,children:e})})})})};T.displayName=`MultiSelect`;const E=s(({"aria-invalid":t,className:n,children:i,onKeyDown:a,onMouseDown:o,validation:s,...c},u)=>{let d=l(S),{inputRef:f}=l(w),p=v.useComboboxContext(),h=t!=null&&t!==`false`?`error`:typeof s==`function`?s():s;return m(`div`,{role:`group`,"data-slot":`multi-select-trigger`,className:e(`cursor-text select-none font-sans text-sm`,`border-form bg-form text-strong flex min-h-9 w-full flex-wrap items-center gap-1 rounded-md border px-3 py-1 has-[[data-slot=multi-select-tag]]:px-1`,`has-focus:outline-hidden has-focus-within:ring-4 has-aria-expanded:ring-4`,`has-focus-within:border-accent-600 has-focus-within:ring-focus-accent has-aria-expanded:border-accent-600 has-aria-expanded:ring-focus-accent`,`data-validation-success:border-success-600 data-validation-success:has-focus-within:border-success-600 data-validation-success:has-focus-within:ring-focus-success data-validation-success:has-aria-expanded:border-success-600 data-validation-success:has-aria-expanded:ring-focus-success`,`data-validation-warning:border-warning-600 data-validation-warning:has-focus-within:border-warning-600 data-validation-warning:has-focus-within:ring-focus-warning data-validation-warning:has-aria-expanded:border-warning-600 data-validation-warning:has-aria-expanded:ring-focus-warning`,`data-validation-error:border-danger-600 data-validation-error:has-focus-within:border-danger-600 data-validation-error:has-focus-within:ring-focus-danger data-validation-error:has-aria-expanded:border-danger-600 data-validation-error:has-aria-expanded:ring-focus-danger`,n),"data-validation":h||void 0,onKeyDown:e=>{e.key===`Escape`&&p?.getState().open&&(e.preventDefault(),p.hide()),a?.(e)},onMouseDown:e=>{e.target instanceof HTMLElement&&!e.target.closest(`button, input, [role='option']`)&&(e.preventDefault(),f.current?.focus()),o?.(e)},ref:r(d,u),...c,children:i})});E.displayName=`MultiSelectTrigger`;const D=s(({className:n,value:i,onRemove:a,locked:o=!1,onKeyDown:s,...c},l)=>{let u=f(null);return h(`span`,{ref:r(u,l),role:`option`,"aria-selected":!0,tabIndex:-1,"data-slot":`multi-select-tag`,"data-locked":o||void 0,className:e(`cursor-default bg-neutral-500/10 border border-neutral-500/20 rounded-xs text-strong inline-flex items-center gap-1 pl-2 pr-0.5 py-0.5 text-sm font-normal`,`focus-visible:outline-hidden focus-visible:border-accent-600/50 focus-visible:ring-3 focus-visible:ring-focus-accent`,n),onKeyDown:e=>{if(o&&(e.key===`Backspace`||e.key===`Delete`)){e.preventDefault(),z(e.currentTarget);return}s?.(e)},...c,children:[i,m(`button`,{type:`button`,"aria-label":`Remove ${i}`,tabIndex:-1,"aria-disabled":o||void 0,className:e(`cursor-pointer text-strong/40 hover:bg-neutral-500/15 hover:text-strong rounded-xs p-0.5`,`aria-disabled:cursor-default aria-disabled:hover:bg-transparent aria-disabled:hover:text-strong/40`),onClick:e=>{if(e.stopPropagation(),o){let e=u.current;e&&z(e);return}a?.()},onMouseDown:e=>{e.preventDefault()},children:m(t,{svg:o?m(y,{}):m(g,{weight:`bold`}),className:`size-4`})})]})});D.displayName=`MultiSelectTag`;const O=({children:e,lockedValues:t=[]})=>{let n=v.useComboboxContext(),r=v.useStoreState(n,`selectedValue`),i=(b(r)?r:void 0)??x,a=f(i);a.current=i;let o=l(C);o.current=t;let s=d(()=>new Set(t),[t]),c=f(new Map),{onInputKeyDownRef:h,inputRef:g}=l(w),_=f(new Set);u(()=>()=>{_.current.forEach(cancelAnimationFrame)},[]);let y=e=>{let t;t=requestAnimationFrame(()=>{_.current.delete(t),e()}),_.current.add(t)},S=e=>{if(n){let t=n.getState().selectedValue;if(!b(t))return;n.setSelectedValue(t.filter(t=>t!==e))}},T=e=>{let t=a.current[e];if(t==null)return;let r=c.current.get(t);r&&(r.focus(),n?.show())},E=()=>{g.current?.focus()},O=(e,t)=>{let n=i[t];switch(e.key){case`ArrowLeft`:e.preventDefault(),t>0&&T(t-1);break;case`ArrowRight`:e.preventDefault(),t<i.length-1?T(t+1):E();break;case`Backspace`:case`Delete`:if(e.preventDefault(),n!=null){if(s.has(n)){let e=c.current.get(n);e&&z(e);break}if(S(n),e.key===`Backspace`)if(t>0){let e=t-1;y(()=>T(e))}else y(()=>{a.current.length>0?T(0):E()});else y(()=>{t<a.current.length?T(t):E()})}break;case`ArrowUp`:case`ArrowDown`:e.preventDefault(),E(),g.current?.dispatchEvent(new KeyboardEvent(`keydown`,{key:e.key,bubbles:!0,cancelable:!0,shiftKey:e.shiftKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,altKey:e.altKey}));break;default:e.key.length===1&&!e.ctrlKey&&!e.metaKey&&E();break}};return h.current=e=>{if(e.key===`ArrowLeft`&&e.currentTarget.selectionStart===0&&e.currentTarget.selectionEnd===0&&i.length>0){e.preventDefault(),T(i.length-1);return}if(e.key===`Backspace`&&e.currentTarget.value===``&&i.length>0){let e=i[i.length-1];if(e!=null)if(o.current.includes(e)){let t=c.current.get(e);t&&z(t)}else S(e)}},m(p,{children:i.map((t,n)=>{let r={value:t,locked:s.has(t),onRemove:()=>{if(s.has(t)){let e=c.current.get(t);e&&z(e);return}S(t)},ref:e=>{e?c.current.set(t,e):c.current.delete(t)},onKeyDown:e=>O(e,n),onClick:()=>T(n)};return e?e(r):m(D,{...r},t)})})};O.displayName=`MultiSelectTagValues`;const k=s(({className:t,onBlur:n,onChange:i,onFocus:a,onKeyDown:o,onValueChange:s,placeholder:c,...u},d)=>{let f=v.useComboboxContext(),{onInputKeyDownRef:p,inputRef:h}=l(w),g=v.useStoreState(f,`selectedValue`),_=((b(g)?g:void 0)?.length??0)>0;return m(v.Combobox,{autoSelect:!0,"data-slot":`multi-select-input`,className:e(`pointer-coarse:text-base min-w-20 flex-1 select-text border-0 bg-transparent text-sm outline-hidden`,`placeholder:select-none placeholder:text-placeholder`,t),onChange:e=>{s?.(e.target.value),i?.(e)},onKeyDown:e=>{p.current?.(e),o?.(e)},onBlur:e=>{e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest(`[data-slot="multi-select-tag"]`)&&f?.show(),n?.(e)},onFocus:e=>{f?.show(),a?.(e)},placeholder:_?void 0:c,ref:r(h,d),...u})});k.displayName=`MultiSelectInput`;const A=s(({asChild:t=!1,backdrop:r=!1,children:i,className:a,modal:o=!0,portalElement:s,sameWidth:u=!0,unmountOnHide:d=!0,...f},p)=>{let h=l(S),g=c(()=>h.current?.getBoundingClientRect()??null,[h]),_=c(e=>typeof s==`function`?s(e):s??h.current?.closest(`[data-mantle-modal-content]`)??e.ownerDocument.body,[s,h]),y=c(e=>!(e.target instanceof Node&&h.current?.contains(e.target)),[h]);return m(v.ComboboxPopover,{"data-slot":`multi-select-content`,className:e(`border-popover bg-popover relative z-50 max-h-96 min-w-32 scrollbar overflow-y-scroll overflow-x-hidden overscroll-y-none rounded-md border shadow-md pt-1 pb-1 has-data-content-footer:pb-0 font-sans flex flex-col gap-px focus:outline-hidden`,a),backdrop:r,getAnchorRect:g,gutter:4,hideOnInteractOutside:y,modal:o,portalElement:_,ref:p,render:t?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,sameWidth:u,unmountOnHide:d,...f,children:i})});A.displayName=`MultiSelectContent`;const j=s(({asChild:r=!1,children:i,className:a,focusOnHover:o=!0,value:s,onClick:c,...u},d)=>{let f=l(C),p=s!=null&&f.current.includes(s);return h(v.ComboboxItem,{"data-slot":`multi-select-item`,className:e(`relative mx-1 cursor-pointer rounded-md pl-2 pr-8 py-1.5 text-strong text-sm font-normal flex min-w-0 items-center gap-2`,`[[role=option]+&]:mt-px`,`data-active-item:bg-active-menu-item`,`aria-disabled:opacity-50`,`aria-selected:bg-selected-menu-item aria-selected:data-active-item:bg-active-selected-menu-item`,a),focusOnHover:o,onClick:e=>{if(p){e.preventDefault();return}c?.(e)},ref:d,render:r?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,resetValueOnSelect:!0,value:s,...u,children:[i,m(v.ComboboxItemCheck,{className:`absolute right-2 flex h-3.5 w-3.5 items-center justify-center`,children:m(t,{svg:m(_,{weight:`bold`}),className:`size-4 text-accent-600`})})]})});j.displayName=`MultiSelectItem`;const M=s(({asChild:e=!1,children:t,...r},i)=>m(v.ComboboxGroup,{"data-slot":`multi-select-group`,className:`mx-1`,ref:i,render:e?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,...r,children:t}));M.displayName=`MultiSelectGroup`;const N=s(({asChild:t=!1,children:r,className:i,...a},o)=>m(v.ComboboxGroupLabel,{"data-slot":`multi-select-group-label`,className:e(`text-muted px-2 py-1 text-xs font-medium`,i),ref:o,render:t?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,...a,children:r}));N.displayName=`MultiSelectGroupLabel`;const P=s(({className:t,children:n,...r},i)=>m(`p`,{"data-slot":`multi-select-group-description`,className:e(`text-muted px-2 pb-1 text-xs`,t),ref:i,...r,children:n}));P.displayName=`MultiSelectGroupDescription`;const F=s(({className:t,...n},r)=>m(i,{"data-slot":`multi-select-separator`,ref:r,className:e(`my-1 w-auto`,t),...n}));F.displayName=`MultiSelectSeparator`;const I=s(({className:t,children:n,...r},i)=>m(`div`,{"data-slot":`multi-select-empty`,className:e(`mx-1 text-muted px-2 py-6 text-center text-sm`,t),ref:i,role:`presentation`,...r,children:n}));I.displayName=`MultiSelectEmpty`;const L=s(({className:t,children:n,...r},i)=>m(`div`,{ref:i,"data-slot":`multi-select-content-footer`,"data-content-footer":!0,className:e(`bg-popover sticky bottom-0 border-t border-popover`,t),...r,children:n}));L.displayName=`MultiSelectContentFooter`;const R={Root:T,Trigger:E,TagValues:O,Input:k,Tag:D,Content:A,ContentFooter:L,Item:j,Group:M,GroupLabel:N,GroupDescription:P,Separator:F,Empty:I};function z(e){a()||e.animate([{transform:`translateX(0)`},{transform:`translateX(-4px)`},{transform:`translateX(4px)`},{transform:`translateX(-4px)`},{transform:`translateX(4px)`},{transform:`translateX(0)`}],{duration:300,easing:`ease-in-out`})}export{R as MultiSelect};
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./icon-bWc5yC3-.js";import{t as n}from"./slot-D_ZUrdEW.js";import{t as r}from"./compose-refs-DFIaEnQH.js";import{n as i}from"./separator-DyOGgFCs.js";import{t as a}from"./use-prefers-reduced-motion-BcwST13S.js";import{createContext as o,forwardRef as s,useCallback as c,useContext as l,useEffect as u,useMemo as d,useRef as f}from"react";import{Fragment as p,jsx as m,jsxs as h}from"react/jsx-runtime";import{XIcon as g}from"@phosphor-icons/react/X";import{CheckIcon as _}from"@phosphor-icons/react/Check";import*as v from"@ariakit/react";import{LockIcon as y}from"@phosphor-icons/react/Lock";const b=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`),x=[],S=o({current:null}),C=o({current:[]}),w=o({onInputKeyDownRef:{current:void 0},inputRef:{current:null}}),T=({children:e,defaultSelectedValue:t=[],...n})=>{let r=f(null),i=f(void 0),a=f(null),o=f([]),s=d(()=>({onInputKeyDownRef:i,inputRef:a}),[]);return m(S.Provider,{value:r,children:m(w.Provider,{value:s,children:m(C.Provider,{value:o,children:m(v.ComboboxProvider,{defaultSelectedValue:t,...n,children:e})})})})};T.displayName=`MultiSelect`;const E=s(({"aria-invalid":t,className:n,children:i,onKeyDown:a,onMouseDown:o,validation:s,...c},u)=>{let d=l(S),{inputRef:f}=l(w),p=v.useComboboxContext(),h=t!=null&&t!==`false`?`error`:typeof s==`function`?s():s;return m(`div`,{role:`group`,"data-slot":`multi-select-trigger`,className:e(`cursor-text select-none font-sans text-sm`,`border-form bg-form text-strong flex min-h-9 w-full flex-wrap items-center gap-1 rounded-md border px-3 py-1 has-[[data-slot=multi-select-tag]]:px-1`,`has-focus:outline-hidden has-focus-within:ring-4 has-aria-expanded:ring-4`,`has-focus-within:border-accent-600 has-focus-within:ring-focus-accent has-aria-expanded:border-accent-600 has-aria-expanded:ring-focus-accent`,`data-validation-success:border-success-600 data-validation-success:has-focus-within:border-success-600 data-validation-success:has-focus-within:ring-focus-success data-validation-success:has-aria-expanded:border-success-600 data-validation-success:has-aria-expanded:ring-focus-success`,`data-validation-warning:border-warning-600 data-validation-warning:has-focus-within:border-warning-600 data-validation-warning:has-focus-within:ring-focus-warning data-validation-warning:has-aria-expanded:border-warning-600 data-validation-warning:has-aria-expanded:ring-focus-warning`,`data-validation-error:border-danger-600 data-validation-error:has-focus-within:border-danger-600 data-validation-error:has-focus-within:ring-focus-danger data-validation-error:has-aria-expanded:border-danger-600 data-validation-error:has-aria-expanded:ring-focus-danger`,n),"data-validation":h||void 0,onKeyDown:e=>{e.key===`Escape`&&p?.getState().open&&(e.preventDefault(),p.hide()),a?.(e)},onMouseDown:e=>{e.target instanceof HTMLElement&&!e.target.closest(`button, input, [role='option']`)&&(e.preventDefault(),f.current?.focus()),o?.(e)},ref:r(d,u),...c,children:i})});E.displayName=`MultiSelectTrigger`;const D=s(({className:n,value:i,onRemove:a,locked:o=!1,onKeyDown:s,...c},l)=>{let u=f(null);return h(`span`,{ref:r(u,l),role:`option`,"aria-selected":!0,tabIndex:-1,"data-slot":`multi-select-tag`,"data-locked":o||void 0,className:e(`cursor-default bg-neutral-500/10 border border-neutral-500/20 rounded-xs text-strong inline-flex items-center gap-1 pl-2 pr-0.5 py-0.5 text-sm font-normal`,`focus-visible:outline-hidden focus-visible:border-accent-600/50 focus-visible:ring-3 focus-visible:ring-focus-accent`,n),onKeyDown:e=>{if(o&&(e.key===`Backspace`||e.key===`Delete`)){e.preventDefault(),z(e.currentTarget);return}s?.(e)},...c,children:[i,m(`button`,{type:`button`,"aria-label":`Remove ${i}`,tabIndex:-1,"aria-disabled":o||void 0,className:e(`cursor-pointer text-strong/40 hover:bg-neutral-500/15 hover:text-strong rounded-xs p-0.5`,`aria-disabled:cursor-default aria-disabled:hover:bg-transparent aria-disabled:hover:text-strong/40`),onClick:e=>{if(e.stopPropagation(),o){let e=u.current;e&&z(e);return}a?.()},onMouseDown:e=>{e.preventDefault()},children:m(t,{svg:o?m(y,{}):m(g,{weight:`bold`}),className:`size-4`})})]})});D.displayName=`MultiSelectTag`;const O=({children:e,lockedValues:t=[]})=>{let n=v.useComboboxContext(),r=v.useStoreState(n,`selectedValue`),i=(b(r)?r:void 0)??x,a=f(i);a.current=i;let o=l(C);o.current=t;let s=d(()=>new Set(t),[t]),c=f(new Map),{onInputKeyDownRef:h,inputRef:g}=l(w),_=f(new Set);u(()=>()=>{_.current.forEach(cancelAnimationFrame)},[]);let y=e=>{let t;t=requestAnimationFrame(()=>{_.current.delete(t),e()}),_.current.add(t)},S=e=>{if(n){let t=n.getState().selectedValue;if(!b(t))return;n.setSelectedValue(t.filter(t=>t!==e))}},T=e=>{let t=a.current[e];if(t==null)return;let r=c.current.get(t);r&&(r.focus(),n?.show())},E=()=>{g.current?.focus()},O=(e,t)=>{let n=i[t];switch(e.key){case`ArrowLeft`:e.preventDefault(),t>0&&T(t-1);break;case`ArrowRight`:e.preventDefault(),t<i.length-1?T(t+1):E();break;case`Backspace`:case`Delete`:if(e.preventDefault(),n!=null){if(s.has(n)){let e=c.current.get(n);e&&z(e);break}if(S(n),e.key===`Backspace`)if(t>0){let e=t-1;y(()=>T(e))}else y(()=>{a.current.length>0?T(0):E()});else y(()=>{t<a.current.length?T(t):E()})}break;case`ArrowUp`:case`ArrowDown`:e.preventDefault(),E(),g.current?.dispatchEvent(new KeyboardEvent(`keydown`,{key:e.key,bubbles:!0,cancelable:!0,shiftKey:e.shiftKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,altKey:e.altKey}));break;default:e.key.length===1&&!e.ctrlKey&&!e.metaKey&&E();break}};return h.current=e=>{if(e.key===`ArrowLeft`&&e.currentTarget.selectionStart===0&&e.currentTarget.selectionEnd===0&&i.length>0){e.preventDefault(),T(i.length-1);return}if(e.key===`Backspace`&&e.currentTarget.value===``&&i.length>0){let e=i[i.length-1];if(e!=null)if(o.current.includes(e)){let t=c.current.get(e);t&&z(t)}else S(e)}},m(p,{children:i.map((t,n)=>{let r={value:t,locked:s.has(t),onRemove:()=>{if(s.has(t)){let e=c.current.get(t);e&&z(e);return}S(t)},ref:e=>{e?c.current.set(t,e):c.current.delete(t)},onKeyDown:e=>O(e,n),onClick:()=>T(n)};return e?e(r):m(D,{...r},t)})})};O.displayName=`MultiSelectTagValues`;const k=s(({className:t,onBlur:n,onChange:i,onFocus:a,onKeyDown:o,onValueChange:s,placeholder:c,...u},d)=>{let f=v.useComboboxContext(),{onInputKeyDownRef:p,inputRef:h}=l(w),g=v.useStoreState(f,`selectedValue`),_=((b(g)?g:void 0)?.length??0)>0;return m(v.Combobox,{autoSelect:!0,"data-slot":`multi-select-input`,className:e(`pointer-coarse:text-base min-w-20 flex-1 select-text border-0 bg-transparent text-sm outline-hidden`,`placeholder:select-none placeholder:text-placeholder`,t),onChange:e=>{s?.(e.target.value),i?.(e)},onKeyDown:e=>{p.current?.(e),o?.(e)},onBlur:e=>{e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest(`[data-slot="multi-select-tag"]`)&&f?.show(),n?.(e)},onFocus:e=>{f?.show(),a?.(e)},placeholder:_?void 0:c,ref:r(h,d),...u})});k.displayName=`MultiSelectInput`;const A=s(({asChild:t=!1,backdrop:r=!1,children:i,className:a,modal:o=!0,portalElement:s,sameWidth:u=!0,unmountOnHide:d=!0,...f},p)=>{let h=l(S),g=c(()=>h.current?.getBoundingClientRect()??null,[h]),_=c(e=>typeof s==`function`?s(e):s??h.current?.closest(`[data-mantle-modal-content]`)??e.ownerDocument.body,[s,h]),y=c(e=>!(e.target instanceof Node&&h.current?.contains(e.target)),[h]);return m(v.ComboboxPopover,{"data-slot":`multi-select-content`,className:e(`border-popover bg-popover relative z-50 max-h-96 min-w-32 scrollbar overflow-y-scroll overflow-x-hidden overscroll-y-none rounded-md border shadow-md pt-1 pb-1 has-data-content-footer:pb-0 font-sans flex flex-col gap-px focus:outline-hidden`,a),backdrop:r,getAnchorRect:g,gutter:4,hideOnInteractOutside:y,modal:o,portalElement:_,ref:p,render:t?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,sameWidth:u,unmountOnHide:d,...f,children:i})});A.displayName=`MultiSelectContent`;const j=s(({asChild:r=!1,children:i,className:a,focusOnHover:o=!0,value:s,onClick:c,...u},d)=>{let f=l(C),p=s!=null&&f.current.includes(s);return h(v.ComboboxItem,{"data-slot":`multi-select-item`,className:e(`relative mx-1 cursor-pointer rounded-md pl-2 pr-8 py-1.5 text-strong text-sm font-normal flex min-w-0 items-center gap-2`,`[[role=option]+&]:mt-px`,`data-active-item:bg-active-menu-item`,`aria-disabled:opacity-50`,`aria-selected:bg-selected-menu-item aria-selected:data-active-item:bg-active-selected-menu-item`,a),focusOnHover:o,onClick:e=>{if(p){e.preventDefault();return}c?.(e)},ref:d,render:r?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,resetValueOnSelect:!0,value:s,...u,children:[i,m(v.ComboboxItemCheck,{className:`absolute right-2 flex h-3.5 w-3.5 items-center justify-center`,children:m(t,{svg:m(_,{weight:`bold`}),className:`size-4 text-accent-600`})})]})});j.displayName=`MultiSelectItem`;const M=s(({asChild:e=!1,children:t,...r},i)=>m(v.ComboboxGroup,{"data-slot":`multi-select-group`,className:`mx-1`,ref:i,render:e?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,...r,children:t}));M.displayName=`MultiSelectGroup`;const N=s(({asChild:t=!1,children:r,className:i,...a},o)=>m(v.ComboboxGroupLabel,{"data-slot":`multi-select-group-label`,className:e(`text-muted px-2 py-1 text-xs font-medium`,i),ref:o,render:t?({ref:e,...t})=>m(n,{ref:e,...t}):void 0,...a,children:r}));N.displayName=`MultiSelectGroupLabel`;const P=s(({className:t,children:n,...r},i)=>m(`p`,{"data-slot":`multi-select-group-description`,className:e(`text-muted px-2 pb-1 text-xs`,t),ref:i,...r,children:n}));P.displayName=`MultiSelectGroupDescription`;const F=s(({className:t,...n},r)=>m(i,{"data-slot":`multi-select-separator`,ref:r,className:e(`my-1 w-auto`,t),...n}));F.displayName=`MultiSelectSeparator`;const I=s(({className:t,children:n,...r},i)=>m(`div`,{"data-slot":`multi-select-empty`,className:e(`mx-1 text-muted px-2 py-6 text-center text-sm`,t),ref:i,role:`presentation`,...r,children:n}));I.displayName=`MultiSelectEmpty`;const L=s(({className:t,children:n,...r},i)=>m(`div`,{ref:i,"data-slot":`multi-select-content-footer`,"data-content-footer":!0,className:e(`bg-popover sticky bottom-0 border-t border-popover`,t),...r,children:n}));L.displayName=`MultiSelectContentFooter`;const R={Root:T,Trigger:E,TagValues:O,Input:k,Tag:D,Content:A,ContentFooter:L,Item:j,Group:M,GroupLabel:N,GroupDescription:P,Separator:F,Empty:I};function z(e){a()||e.animate([{transform:`translateX(0)`},{transform:`translateX(-4px)`},{transform:`translateX(4px)`},{transform:`translateX(-4px)`},{transform:`translateX(4px)`},{transform:`translateX(0)`}],{duration:300,easing:`ease-in-out`})}export{R as MultiSelect};
|
|
2
2
|
//# sourceMappingURL=multi-select.js.map
|
package/dist/pagination.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as WithAsChild } from "./as-child-CJ2vTesV.js";
|
|
2
|
-
import { t as ButtonGroup } from "./index-
|
|
2
|
+
import { t as ButtonGroup } from "./index-DU3SQJ46.js";
|
|
3
3
|
import { t as Select } from "./select-DNJli9JO.js";
|
|
4
4
|
import * as _$react from "react";
|
|
5
5
|
import { ComponentProps } from "react";
|
package/dist/pagination.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./slot-D_ZUrdEW.js";import{t as n}from"./icon-button-
|
|
1
|
+
import{t as e}from"./cx-D1HYnpvA.js";import{t}from"./slot-D_ZUrdEW.js";import{t as n}from"./icon-button-ZKN0sRIJ.js";import{t as r}from"./button-POMJ-20y.js";import{n as i}from"./separator-DyOGgFCs.js";import{t as a}from"./select-LJmfG--I.js";import{createContext as o,forwardRef as s,useContext as c,useEffect as l,useState as u}from"react";import d from"tiny-invariant";import{jsx as f,jsxs as p}from"react/jsx-runtime";import{CaretLeftIcon as m}from"@phosphor-icons/react/CaretLeft";import{CaretRightIcon as h}from"@phosphor-icons/react/CaretRight";const g=o(void 0),_=s(({className:t,children:n,defaultPageSize:r,...i},a)=>{let[o,s]=u(r);return f(g.Provider,{value:{defaultPageSize:r,pageSize:o,setPageSize:s},children:f(`div`,{"data-slot":`cursor-pagination`,className:e(`inline-flex items-center justify-between gap-2`,t),ref:a,...i,children:n})})});_.displayName=`CursorPagination`;const v=s(({hasNextPage:e,hasPreviousPage:t,onNextPage:a,onPreviousPage:o,...s},c)=>p(r,{"data-slot":`cursor-pagination-buttons`,appearance:`panel`,ref:c,...s,children:[f(n,{"data-slot":`cursor-pagination-previous`,appearance:`ghost`,disabled:!t,icon:f(m,{}),label:`Previous page`,onClick:o,size:`sm`,type:`button`}),f(i,{"data-slot":`cursor-pagination-separator`,orientation:`vertical`,className:`min-h-5`}),f(n,{"data-slot":`cursor-pagination-next`,appearance:`ghost`,disabled:!e,icon:f(h,{}),label:`Next page`,onClick:a,size:`sm`,type:`button`})]}));v.displayName=`CursorButtons`;const y=[5,10,20,50,100],b=s(({className:t,pageSizes:n=y,onChangePageSize:r,...i},o)=>{let s=c(g);return d(s,`CursorPageSizeSelect must be used as a child of a CursorPagination component`),d(n.includes(s.defaultPageSize),`CursorPagination.defaultPageSize must be included in CursorPageSizeSelect.pageSizes`),d(n.includes(s.pageSize),`CursorPagination.pageSize must be included in CursorPageSizeSelect.pageSizes`),p(a.Root,{defaultValue:`${s.pageSize}`,onValueChange:e=>{let t=Number.parseInt(e,10);Number.isNaN(t)&&(t=s.defaultPageSize),s.setPageSize(t),r?.(t)},children:[f(a.Trigger,{ref:o,"data-slot":`cursor-pagination-page-size-select`,className:e(`w-auto min-w-36`,t),value:s.pageSize,...i,children:f(a.Value,{})}),f(a.Content,{width:`trigger`,children:n.map(e=>p(a.Item,{value:`${e}`,children:[e,` per page`]},e))})]})});b.displayName=`CursorPageSizeSelect`;function x({asChild:n=!1,className:r,...i}){let a=c(g);return d(a,`CursorPageSizeValue must be used as a child of a CursorPagination component`),p(n?t:`span`,{"data-slot":`cursor-pagination-page-size-value`,className:e(`text-muted text-sm font-normal`,r),...i,children:[a.pageSize,` per page`]})}x.displayName=`CursorPageSizeValue`;const S={Root:_,Buttons:v,PageSizeSelect:b,PageSizeValue:x};function C({listSize:e,pageSize:t}){let[n,r]=u(1),[i,a]=u(t);l(()=>{a(t),r(1)},[t]),l(()=>{r(1)},[e]);let o=Math.ceil(e/i),s=(n-1)*i,c=n>1,d=n<o;function f(e){r(Math.max(1,Math.min(e,o)))}function p(){d&&r(e=>Math.min(e+1,o))}function m(){c&&r(e=>Math.max(e-1,1))}function h(e){a(e),r(1)}function g(){r(o)}function _(){r(1)}return{currentPage:n,goToFirstPage:_,goToLastPage:g,goToPage:f,hasNextPage:d,hasPreviousPage:c,nextPage:p,offset:s,pageSize:i,previousPage:m,setPageSize:h,totalPages:o}}function w(e,t){return e.slice(t.offset,t.offset+t.pageSize)}export{S as CursorPagination,w as getOffsetPaginatedSlice,C as useOffsetPagination};
|
|
2
2
|
//# sourceMappingURL=pagination.js.map
|
package/dist/pagination.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","names":[],"sources":["../src/components/pagination/cursor-pagination.tsx","../src/components/pagination/use-offset-pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport { CaretLeftIcon } from \"@phosphor-icons/react/CaretLeft\";\nimport { CaretRightIcon } from \"@phosphor-icons/react/CaretRight\";\nimport {\n\ttype ComponentProps,\n\ttype ComponentRef,\n\tcreateContext,\n\tforwardRef,\n\tuseContext,\n\tuseState,\n} from \"react\";\nimport invariant from \"tiny-invariant\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { ButtonGroup, IconButton } from \"../button/index.js\";\nimport { Select } from \"../select/select.js\";\nimport { Separator } from \"../separator/separator.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype CursorPaginationContextValue = {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n\t/**\n\t * The current number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * A function to set the number of items per page.\n\t */\n\tsetPageSize: (value: number) => void;\n};\n\nconst CursorPaginationContext = createContext<CursorPaginationContextValue | undefined>(undefined);\n\ntype CursorPaginationProps = ComponentProps<\"div\"> & {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n};\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst Root = forwardRef<HTMLDivElement, CursorPaginationProps>(\n\t({ className, children, defaultPageSize, ...props }, ref) => {\n\t\tconst [pageSize, setPageSize] = useState<number>(defaultPageSize);\n\n\t\treturn (\n\t\t\t<CursorPaginationContext.Provider value={{ defaultPageSize, pageSize, setPageSize }}>\n\t\t\t\t<div\n\t\t\t\t\tclassName={cx(\"inline-flex items-center justify-between gap-2\", className)}\n\t\t\t\t\tref={ref}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</CursorPaginationContext.Provider>\n\t\t);\n\t},\n);\nRoot.displayName = \"CursorPagination\";\n\ntype CursorButtonsProps = Omit<ComponentProps<typeof ButtonGroup>, \"appearance\"> & {\n\t/**\n\t * Whether there is a next page of data to load.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Whether there is a previous page of data to load.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * A callback that is called when the next page button is clicked.\n\t */\n\tonNextPage?: () => void;\n\t/**\n\t * A callback that is called when the previous page button is clicked.\n\t */\n\tonPreviousPage?: () => void;\n};\n\n/**\n * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n *\n * @example\n * ```tsx\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={() => loadNextPage()}\n * onPreviousPage={() => loadPreviousPage()}\n * />\n * ```\n */\nconst Buttons = forwardRef<ComponentRef<typeof ButtonGroup>, CursorButtonsProps>(\n\t({ hasNextPage, hasPreviousPage, onNextPage, onPreviousPage, ...props }, ref) => {\n\t\t// TODO(cody): this _feels_ like a good spot for left and right arrow keys to navigate between pages when focused on the buttons\n\n\t\treturn (\n\t\t\t<ButtonGroup appearance=\"panel\" ref={ref} {...props}>\n\t\t\t\t<IconButton\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasPreviousPage}\n\t\t\t\t\ticon={<CaretLeftIcon />}\n\t\t\t\t\tlabel=\"Previous page\"\n\t\t\t\t\tonClick={onPreviousPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t\t<Separator orientation=\"vertical\" className=\"min-h-5\" />\n\t\t\t\t<IconButton\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasNextPage}\n\t\t\t\t\ticon={<CaretRightIcon />}\n\t\t\t\t\tlabel=\"Next page\"\n\t\t\t\t\tonClick={onNextPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t</ButtonGroup>\n\t\t);\n\t},\n);\nButtons.displayName = \"CursorButtons\";\n\nconst defaultPageSizes = [5, 10, 20, 50, 100] as const;\n\ntype CursorPageSizeSelectProps = Omit<ComponentProps<typeof Select.Trigger>, \"children\"> & {\n\t/**\n\t * A list of page sizes to choose from. The default page size must be included in this list.\n\t */\n\tpageSizes?: typeof defaultPageSizes | readonly number[];\n\t/**\n\t * A callback that is called when the page size is changed.\n\t */\n\tonChangePageSize?: (value: number) => void;\n};\n\n/**\n * A select input for changing the number of items per page when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n *\n * @example\n * ```tsx\n * <CursorPagination.PageSizeSelect\n * pageSizes={[10, 20, 50, 100]}\n * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n * />\n * ```\n */\nconst PageSizeSelect = forwardRef<ComponentRef<typeof Select.Trigger>, CursorPageSizeSelectProps>(\n\t({ className, pageSizes = defaultPageSizes, onChangePageSize, ...rest }, ref) => {\n\t\tconst ctx = useContext(CursorPaginationContext);\n\n\t\tinvariant(ctx, \"CursorPageSizeSelect must be used as a child of a CursorPagination component\");\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.defaultPageSize),\n\t\t\t\"CursorPagination.defaultPageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.pageSize),\n\t\t\t\"CursorPagination.pageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\treturn (\n\t\t\t<Select.Root\n\t\t\t\tdefaultValue={`${ctx.pageSize}`}\n\t\t\t\tonValueChange={(value) => {\n\t\t\t\t\tlet newPageSize = Number.parseInt(value, 10);\n\t\t\t\t\tif (Number.isNaN(newPageSize)) {\n\t\t\t\t\t\tnewPageSize = ctx.defaultPageSize;\n\t\t\t\t\t}\n\t\t\t\t\tctx.setPageSize(newPageSize);\n\t\t\t\t\tonChangePageSize?.(newPageSize);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Select.Trigger\n\t\t\t\t\tref={ref}\n\t\t\t\t\tclassName={cx(\"w-auto min-w-36\", className)}\n\t\t\t\t\tvalue={ctx.pageSize}\n\t\t\t\t\t{...rest}\n\t\t\t\t>\n\t\t\t\t\t<Select.Value />\n\t\t\t\t</Select.Trigger>\n\t\t\t\t<Select.Content width=\"trigger\">\n\t\t\t\t\t{pageSizes.map((size) => (\n\t\t\t\t\t\t<Select.Item key={size} value={`${size}`}>\n\t\t\t\t\t\t\t{size} per page\n\t\t\t\t\t\t</Select.Item>\n\t\t\t\t\t))}\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Root>\n\t\t);\n\t},\n);\nPageSizeSelect.displayName = \"CursorPageSizeSelect\";\n\ntype CursorPageSizeValueProps = Omit<ComponentProps<\"span\">, \"children\"> & WithAsChild;\n\n/**\n * Displays the current page size when using cursor-based pagination as a read-only value.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n *\n * @example\n * ```tsx\n * <div className=\"flex items-center gap-2\">\n * <span>Items per page:</span>\n * <CursorPagination.PageSizeValue />\n * </div>\n * ```\n */\nfunction PageSizeValue({ asChild = false, className, ...props }: CursorPageSizeValueProps) {\n\tconst ctx = useContext(CursorPaginationContext);\n\n\tinvariant(ctx, \"CursorPageSizeValue must be used as a child of a CursorPagination component\");\n\n\tconst Component = asChild ? Slot : \"span\";\n\n\treturn (\n\t\t<Component className={cx(\"text-muted text-sm font-normal\", className)} {...props}>\n\t\t\t{ctx.pageSize} per page\n\t\t</Component>\n\t);\n}\nPageSizeValue.displayName = \"CursorPageSizeValue\";\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination\n *\n * @example\n * Composition:\n * ```\n * CursorPagination.Root\n * ├── CursorPagination.PageSizeSelect\n * ├── CursorPagination.PageSizeValue\n * └── CursorPagination.Buttons\n * ```\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst CursorPagination = {\n\t/**\n\t * The root container of the cursor pagination component.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Root defaultPageSize={10}>\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={handleNext}\n\t * onPreviousPage={handlePrevious}\n\t * />\n\t * <CursorPagination.PageSizeSelect />\n\t * </CursorPagination.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={() => loadNextPage()}\n\t * onPreviousPage={() => loadPreviousPage()}\n\t * />\n\t * ```\n\t */\n\tButtons,\n\t/**\n\t * A select input for changing the number of items per page when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.PageSizeSelect\n\t * pageSizes={[10, 20, 50, 100]}\n\t * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n\t * />\n\t * ```\n\t */\n\tPageSizeSelect,\n\t/**\n\t * Displays the current page size when using cursor-based pagination as a read-only value.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n\t *\n\t * @example\n\t * ```tsx\n\t * <div className=\"flex items-center gap-2\">\n\t * <span>Items per page:</span>\n\t * <CursorPagination.PageSizeValue />\n\t * </div>\n\t * ```\n\t */\n\tPageSizeValue,\n} as const;\n\nexport {\n\t//,\n\tCursorPagination,\n};\n\nexport type {\n\t//,\n\tCursorButtonsProps,\n\tCursorPageSizeSelectProps,\n\tCursorPageSizeValueProps,\n\tCursorPaginationProps,\n};\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\ntype UseOffsetPaginationProps = {\n\t/**\n\t * The total number of items in the list to be paginated.\n\t */\n\tlistSize: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n};\n\ntype OffsetPaginationState = {\n\t/**\n\t * The current page number, 1-indexed (starting at 1).\n\t */\n\tcurrentPage: number;\n\t/**\n\t * Whether there is a previous page.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * Whether there is a next page.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Go to a specific page.\n\t */\n\tgoToPage: (page: number) => void;\n\t/**\n\t * Go to the first page.\n\t */\n\tgoToFirstPage: () => void;\n\t/**\n\t * Go to the last page.\n\t */\n\tgoToLastPage: () => void;\n\t/**\n\t * Go to the next page.\n\t */\n\tnextPage: () => void;\n\t/**\n\t * The offset of the current page in the list.\n\t */\n\toffset: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * Go to the previous page.\n\t */\n\tpreviousPage: () => void;\n\t/**\n\t * Set the number of items per page. This will reset the current page to the first page.\n\t */\n\tsetPageSize: (size: number) => void;\n\t/**\n\t * The total number of pages.\n\t */\n\ttotalPages: number;\n};\n\n/**\n * A headless hook for managing offset-based pagination state\n *\n * @example\n * ```tsx\n * const pagination = useOffsetPagination({\n * listSize: 150,\n * pageSize: 10\n * });\n *\n * return (\n * <div>\n * <p>Page {pagination.currentPage} of {pagination.totalPages}</p>\n * <button onClick={pagination.previousPage} disabled={!pagination.hasPreviousPage}>\n * Previous\n * </button>\n * <button onClick={pagination.nextPage} disabled={!pagination.hasNextPage}>\n * Next\n * </button>\n * </div>\n * );\n * ```\n */\nfunction useOffsetPagination({\n\tlistSize,\n\tpageSize,\n}: UseOffsetPaginationProps): OffsetPaginationState {\n\tconst [currentPage, setCurrentPage] = useState(1);\n\tconst [currentPageSize, setCurrentPageSize] = useState(pageSize);\n\n\t// Reset the current page to 1 when the page size prop changes\n\tuseEffect(() => {\n\t\tsetCurrentPageSize(pageSize);\n\t\tsetCurrentPage(1);\n\t}, [pageSize]);\n\n\t// Reset the current page to 1 when the list size prop changes\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: when the listSize prop changes, we want to reset the current page to the start\n\tuseEffect(() => {\n\t\tsetCurrentPage(1);\n\t}, [listSize]);\n\n\tconst totalPages = Math.ceil(listSize / currentPageSize);\n\tconst offset = (currentPage - 1) * currentPageSize;\n\n\tconst hasPreviousPage = currentPage > 1;\n\tconst hasNextPage = currentPage < totalPages;\n\n\tfunction goToPage(page: number) {\n\t\tconst clampedPage = Math.max(1, Math.min(page, totalPages));\n\t\tsetCurrentPage(clampedPage);\n\t}\n\n\tfunction nextPage() {\n\t\tif (hasNextPage) {\n\t\t\tsetCurrentPage((prev) => Math.min(prev + 1, totalPages));\n\t\t}\n\t}\n\n\tfunction previousPage() {\n\t\tif (hasPreviousPage) {\n\t\t\tsetCurrentPage((prev) => Math.max(prev - 1, 1));\n\t\t}\n\t}\n\n\tfunction setPageSize(size: number) {\n\t\tsetCurrentPageSize(size);\n\t\tsetCurrentPage(1); // reset to the first page when page size changes\n\t}\n\n\tfunction goToLastPage() {\n\t\tsetCurrentPage(totalPages);\n\t}\n\n\tfunction goToFirstPage() {\n\t\tsetCurrentPage(1);\n\t}\n\n\treturn {\n\t\tcurrentPage,\n\t\tgoToFirstPage,\n\t\tgoToLastPage,\n\t\tgoToPage,\n\t\thasNextPage,\n\t\thasPreviousPage,\n\t\tnextPage,\n\t\toffset,\n\t\tpageSize: currentPageSize,\n\t\tpreviousPage,\n\t\tsetPageSize,\n\t\ttotalPages,\n\t};\n}\n\n/**\n * Get a paginated slice of a list based on the current offset pagination state.\n *\n * @example\n * ```tsx\n * const data = ['a', 'b', 'c', 'd', 'e', 'f'];\n * const pagination = useOffsetPagination({ listSize: data.length, pageSize: 2 });\n * const currentPageData = getOffsetPaginatedSlice(data, pagination);\n * // Returns: ['a', 'b'] for page 1, ['c', 'd'] for page 2, etc.\n * ```\n */\nfunction getOffsetPaginatedSlice<T>(list: readonly T[], pagination: OffsetPaginationState): T[] {\n\treturn list.slice(pagination.offset, pagination.offset + pagination.pageSize);\n}\n\nexport {\n\t//,\n\tgetOffsetPaginatedSlice,\n\tuseOffsetPagination,\n};\n\nexport type {\n\t//,\n\tOffsetPaginationState,\n\tUseOffsetPaginationProps,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pagination.js","names":[],"sources":["../src/components/pagination/cursor-pagination.tsx","../src/components/pagination/use-offset-pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport { CaretLeftIcon } from \"@phosphor-icons/react/CaretLeft\";\nimport { CaretRightIcon } from \"@phosphor-icons/react/CaretRight\";\nimport {\n\ttype ComponentProps,\n\ttype ComponentRef,\n\tcreateContext,\n\tforwardRef,\n\tuseContext,\n\tuseState,\n} from \"react\";\nimport invariant from \"tiny-invariant\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { ButtonGroup, IconButton } from \"../button/index.js\";\nimport { Select } from \"../select/select.js\";\nimport { Separator } from \"../separator/separator.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype CursorPaginationContextValue = {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n\t/**\n\t * The current number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * A function to set the number of items per page.\n\t */\n\tsetPageSize: (value: number) => void;\n};\n\nconst CursorPaginationContext = createContext<CursorPaginationContextValue | undefined>(undefined);\n\ntype CursorPaginationProps = ComponentProps<\"div\"> & {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n};\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst Root = forwardRef<HTMLDivElement, CursorPaginationProps>(\n\t({ className, children, defaultPageSize, ...props }, ref) => {\n\t\tconst [pageSize, setPageSize] = useState<number>(defaultPageSize);\n\n\t\treturn (\n\t\t\t<CursorPaginationContext.Provider value={{ defaultPageSize, pageSize, setPageSize }}>\n\t\t\t\t<div\n\t\t\t\t\tdata-slot=\"cursor-pagination\"\n\t\t\t\t\tclassName={cx(\"inline-flex items-center justify-between gap-2\", className)}\n\t\t\t\t\tref={ref}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</CursorPaginationContext.Provider>\n\t\t);\n\t},\n);\nRoot.displayName = \"CursorPagination\";\n\ntype CursorButtonsProps = Omit<ComponentProps<typeof ButtonGroup>, \"appearance\"> & {\n\t/**\n\t * Whether there is a next page of data to load.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Whether there is a previous page of data to load.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * A callback that is called when the next page button is clicked.\n\t */\n\tonNextPage?: () => void;\n\t/**\n\t * A callback that is called when the previous page button is clicked.\n\t */\n\tonPreviousPage?: () => void;\n};\n\n/**\n * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n *\n * @example\n * ```tsx\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={() => loadNextPage()}\n * onPreviousPage={() => loadPreviousPage()}\n * />\n * ```\n */\nconst Buttons = forwardRef<ComponentRef<typeof ButtonGroup>, CursorButtonsProps>(\n\t({ hasNextPage, hasPreviousPage, onNextPage, onPreviousPage, ...props }, ref) => {\n\t\t// TODO(cody): this _feels_ like a good spot for left and right arrow keys to navigate between pages when focused on the buttons\n\n\t\treturn (\n\t\t\t<ButtonGroup data-slot=\"cursor-pagination-buttons\" appearance=\"panel\" ref={ref} {...props}>\n\t\t\t\t<IconButton\n\t\t\t\t\tdata-slot=\"cursor-pagination-previous\"\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasPreviousPage}\n\t\t\t\t\ticon={<CaretLeftIcon />}\n\t\t\t\t\tlabel=\"Previous page\"\n\t\t\t\t\tonClick={onPreviousPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t\t<Separator\n\t\t\t\t\tdata-slot=\"cursor-pagination-separator\"\n\t\t\t\t\torientation=\"vertical\"\n\t\t\t\t\tclassName=\"min-h-5\"\n\t\t\t\t/>\n\t\t\t\t<IconButton\n\t\t\t\t\tdata-slot=\"cursor-pagination-next\"\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasNextPage}\n\t\t\t\t\ticon={<CaretRightIcon />}\n\t\t\t\t\tlabel=\"Next page\"\n\t\t\t\t\tonClick={onNextPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t</ButtonGroup>\n\t\t);\n\t},\n);\nButtons.displayName = \"CursorButtons\";\n\nconst defaultPageSizes = [5, 10, 20, 50, 100] as const;\n\ntype CursorPageSizeSelectProps = Omit<ComponentProps<typeof Select.Trigger>, \"children\"> & {\n\t/**\n\t * A list of page sizes to choose from. The default page size must be included in this list.\n\t */\n\tpageSizes?: typeof defaultPageSizes | readonly number[];\n\t/**\n\t * A callback that is called when the page size is changed.\n\t */\n\tonChangePageSize?: (value: number) => void;\n};\n\n/**\n * A select input for changing the number of items per page when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n *\n * @example\n * ```tsx\n * <CursorPagination.PageSizeSelect\n * pageSizes={[10, 20, 50, 100]}\n * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n * />\n * ```\n */\nconst PageSizeSelect = forwardRef<ComponentRef<typeof Select.Trigger>, CursorPageSizeSelectProps>(\n\t({ className, pageSizes = defaultPageSizes, onChangePageSize, ...rest }, ref) => {\n\t\tconst ctx = useContext(CursorPaginationContext);\n\n\t\tinvariant(ctx, \"CursorPageSizeSelect must be used as a child of a CursorPagination component\");\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.defaultPageSize),\n\t\t\t\"CursorPagination.defaultPageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.pageSize),\n\t\t\t\"CursorPagination.pageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\treturn (\n\t\t\t<Select.Root\n\t\t\t\tdefaultValue={`${ctx.pageSize}`}\n\t\t\t\tonValueChange={(value) => {\n\t\t\t\t\tlet newPageSize = Number.parseInt(value, 10);\n\t\t\t\t\tif (Number.isNaN(newPageSize)) {\n\t\t\t\t\t\tnewPageSize = ctx.defaultPageSize;\n\t\t\t\t\t}\n\t\t\t\t\tctx.setPageSize(newPageSize);\n\t\t\t\t\tonChangePageSize?.(newPageSize);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Select.Trigger\n\t\t\t\t\tref={ref}\n\t\t\t\t\tdata-slot=\"cursor-pagination-page-size-select\"\n\t\t\t\t\tclassName={cx(\"w-auto min-w-36\", className)}\n\t\t\t\t\tvalue={ctx.pageSize}\n\t\t\t\t\t{...rest}\n\t\t\t\t>\n\t\t\t\t\t<Select.Value />\n\t\t\t\t</Select.Trigger>\n\t\t\t\t<Select.Content width=\"trigger\">\n\t\t\t\t\t{pageSizes.map((size) => (\n\t\t\t\t\t\t<Select.Item key={size} value={`${size}`}>\n\t\t\t\t\t\t\t{size} per page\n\t\t\t\t\t\t</Select.Item>\n\t\t\t\t\t))}\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Root>\n\t\t);\n\t},\n);\nPageSizeSelect.displayName = \"CursorPageSizeSelect\";\n\ntype CursorPageSizeValueProps = Omit<ComponentProps<\"span\">, \"children\"> & WithAsChild;\n\n/**\n * Displays the current page size when using cursor-based pagination as a read-only value.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n *\n * @example\n * ```tsx\n * <div className=\"flex items-center gap-2\">\n * <span>Items per page:</span>\n * <CursorPagination.PageSizeValue />\n * </div>\n * ```\n */\nfunction PageSizeValue({ asChild = false, className, ...props }: CursorPageSizeValueProps) {\n\tconst ctx = useContext(CursorPaginationContext);\n\n\tinvariant(ctx, \"CursorPageSizeValue must be used as a child of a CursorPagination component\");\n\n\tconst Component = asChild ? Slot : \"span\";\n\n\treturn (\n\t\t<Component\n\t\t\tdata-slot=\"cursor-pagination-page-size-value\"\n\t\t\tclassName={cx(\"text-muted text-sm font-normal\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{ctx.pageSize} per page\n\t\t</Component>\n\t);\n}\nPageSizeValue.displayName = \"CursorPageSizeValue\";\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination\n *\n * @example\n * Composition:\n * ```\n * CursorPagination.Root\n * ├── CursorPagination.PageSizeSelect\n * ├── CursorPagination.PageSizeValue\n * └── CursorPagination.Buttons\n * ```\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst CursorPagination = {\n\t/**\n\t * The root container of the cursor pagination component.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Root defaultPageSize={10}>\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={handleNext}\n\t * onPreviousPage={handlePrevious}\n\t * />\n\t * <CursorPagination.PageSizeSelect />\n\t * </CursorPagination.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={() => loadNextPage()}\n\t * onPreviousPage={() => loadPreviousPage()}\n\t * />\n\t * ```\n\t */\n\tButtons,\n\t/**\n\t * A select input for changing the number of items per page when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.PageSizeSelect\n\t * pageSizes={[10, 20, 50, 100]}\n\t * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n\t * />\n\t * ```\n\t */\n\tPageSizeSelect,\n\t/**\n\t * Displays the current page size when using cursor-based pagination as a read-only value.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n\t *\n\t * @example\n\t * ```tsx\n\t * <div className=\"flex items-center gap-2\">\n\t * <span>Items per page:</span>\n\t * <CursorPagination.PageSizeValue />\n\t * </div>\n\t * ```\n\t */\n\tPageSizeValue,\n} as const;\n\nexport {\n\t//,\n\tCursorPagination,\n};\n\nexport type {\n\t//,\n\tCursorButtonsProps,\n\tCursorPageSizeSelectProps,\n\tCursorPageSizeValueProps,\n\tCursorPaginationProps,\n};\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\ntype UseOffsetPaginationProps = {\n\t/**\n\t * The total number of items in the list to be paginated.\n\t */\n\tlistSize: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n};\n\ntype OffsetPaginationState = {\n\t/**\n\t * The current page number, 1-indexed (starting at 1).\n\t */\n\tcurrentPage: number;\n\t/**\n\t * Whether there is a previous page.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * Whether there is a next page.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Go to a specific page.\n\t */\n\tgoToPage: (page: number) => void;\n\t/**\n\t * Go to the first page.\n\t */\n\tgoToFirstPage: () => void;\n\t/**\n\t * Go to the last page.\n\t */\n\tgoToLastPage: () => void;\n\t/**\n\t * Go to the next page.\n\t */\n\tnextPage: () => void;\n\t/**\n\t * The offset of the current page in the list.\n\t */\n\toffset: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * Go to the previous page.\n\t */\n\tpreviousPage: () => void;\n\t/**\n\t * Set the number of items per page. This will reset the current page to the first page.\n\t */\n\tsetPageSize: (size: number) => void;\n\t/**\n\t * The total number of pages.\n\t */\n\ttotalPages: number;\n};\n\n/**\n * A headless hook for managing offset-based pagination state\n *\n * @example\n * ```tsx\n * const pagination = useOffsetPagination({\n * listSize: 150,\n * pageSize: 10\n * });\n *\n * return (\n * <div>\n * <p>Page {pagination.currentPage} of {pagination.totalPages}</p>\n * <button onClick={pagination.previousPage} disabled={!pagination.hasPreviousPage}>\n * Previous\n * </button>\n * <button onClick={pagination.nextPage} disabled={!pagination.hasNextPage}>\n * Next\n * </button>\n * </div>\n * );\n * ```\n */\nfunction useOffsetPagination({\n\tlistSize,\n\tpageSize,\n}: UseOffsetPaginationProps): OffsetPaginationState {\n\tconst [currentPage, setCurrentPage] = useState(1);\n\tconst [currentPageSize, setCurrentPageSize] = useState(pageSize);\n\n\t// Reset the current page to 1 when the page size prop changes\n\tuseEffect(() => {\n\t\tsetCurrentPageSize(pageSize);\n\t\tsetCurrentPage(1);\n\t}, [pageSize]);\n\n\t// Reset the current page to 1 when the list size prop changes\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: when the listSize prop changes, we want to reset the current page to the start\n\tuseEffect(() => {\n\t\tsetCurrentPage(1);\n\t}, [listSize]);\n\n\tconst totalPages = Math.ceil(listSize / currentPageSize);\n\tconst offset = (currentPage - 1) * currentPageSize;\n\n\tconst hasPreviousPage = currentPage > 1;\n\tconst hasNextPage = currentPage < totalPages;\n\n\tfunction goToPage(page: number) {\n\t\tconst clampedPage = Math.max(1, Math.min(page, totalPages));\n\t\tsetCurrentPage(clampedPage);\n\t}\n\n\tfunction nextPage() {\n\t\tif (hasNextPage) {\n\t\t\tsetCurrentPage((prev) => Math.min(prev + 1, totalPages));\n\t\t}\n\t}\n\n\tfunction previousPage() {\n\t\tif (hasPreviousPage) {\n\t\t\tsetCurrentPage((prev) => Math.max(prev - 1, 1));\n\t\t}\n\t}\n\n\tfunction setPageSize(size: number) {\n\t\tsetCurrentPageSize(size);\n\t\tsetCurrentPage(1); // reset to the first page when page size changes\n\t}\n\n\tfunction goToLastPage() {\n\t\tsetCurrentPage(totalPages);\n\t}\n\n\tfunction goToFirstPage() {\n\t\tsetCurrentPage(1);\n\t}\n\n\treturn {\n\t\tcurrentPage,\n\t\tgoToFirstPage,\n\t\tgoToLastPage,\n\t\tgoToPage,\n\t\thasNextPage,\n\t\thasPreviousPage,\n\t\tnextPage,\n\t\toffset,\n\t\tpageSize: currentPageSize,\n\t\tpreviousPage,\n\t\tsetPageSize,\n\t\ttotalPages,\n\t};\n}\n\n/**\n * Get a paginated slice of a list based on the current offset pagination state.\n *\n * @example\n * ```tsx\n * const data = ['a', 'b', 'c', 'd', 'e', 'f'];\n * const pagination = useOffsetPagination({ listSize: data.length, pageSize: 2 });\n * const currentPageData = getOffsetPaginatedSlice(data, pagination);\n * // Returns: ['a', 'b'] for page 1, ['c', 'd'] for page 2, etc.\n * ```\n */\nfunction getOffsetPaginatedSlice<T>(list: readonly T[], pagination: OffsetPaginationState): T[] {\n\treturn list.slice(pagination.offset, pagination.offset + pagination.pageSize);\n}\n\nexport {\n\t//,\n\tgetOffsetPaginatedSlice,\n\tuseOffsetPagination,\n};\n\nexport type {\n\t//,\n\tOffsetPaginationState,\n\tUseOffsetPaginationProps,\n};\n"],"mappings":"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"}
|