@cryptlex/web-components 6.6.6-alpha67 → 6.6.6-alpha69
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/components/checkbox.js +1 -1
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/duration-field.js +1 -1
- package/dist/components/duration-field.js.map +1 -1
- package/dist/components/id-search.js +1 -1
- package/dist/components/id-search.js.map +1 -1
- package/dist/components/multi-select.js +1 -1
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/numberfield.js +1 -1
- package/dist/components/numberfield.js.map +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/select.js.map +1 -1
- package/dist/components/textfield.js +1 -1
- package/dist/components/textfield.js.map +1 -1
- package/dist/utilities/form-context.d.ts +1 -0
- package/dist/utilities/form-context.js +1 -1
- package/dist/utilities/form-context.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as e,Fragment as k,jsxs as v}from"react/jsx-runtime";import{useId as C}from"react";import{Checkbox as y,composeRenderProps as l,CheckboxGroup as N}from"react-aria-components";import{useFieldContext as I}from"../utilities/form-context.js";import{classNames as r}from"../utilities/theme.js";import{FormField as w,labelVariants as B}from"./form.js";import{IcMinus as F,IcCheck as j}from"./icons.js";import"@tanstack/react-form";import"clsx";import"class-variance-authority";const i="group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50",a="group-data-[invalid]/checkbox:border-destructive",u="focus:outline-none focus-visible:outline-none",b="group-data-[selected]/checkbox:bg-primary",S="relative shrink-0 h-6 w-11 rounded-full border border-input bg-elevation-2 transition-colors duration-200",z="absolute top-1/2 -translate-y-1/2 left-0.5 h-5 w-5 rounded-full bg-background border border-input transition-transform duration-200",D="flex size-input shrink-0 items-center bg-elevation-2 justify-center border border-input text-current ring-offset-background",H=N;function G({className:o,label:t,description:m,errorMessage:h,requiredIndicator:p,variant:x="checkbox",...c}){const g=C(),n=c.id||g,f=x==="switch";return e("div",{className:"group form-field",children:e(w,{label:t,description:m,errorMessage:h,requiredIndicator:p,htmlFor:n,children:e(y,{className:l(o,d=>r("group/checkbox cursor-pointer relative focus-ring flex items-center gap-x-2 disabled-muted",B,d)),id:n,...c,children:l(e(k,{}),(d,s)=>f?e("div",{className:r(S,b,i,a,"group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive",u),children:e("div",{className:r(z,"group-data-[selected]/checkbox:translate-x-4.5",i,a)})}):e("div",{className:r(D,"group-data-[indeterminate]/checkbox:bg-primary",b,"group-data-[indeterminate]/checkbox:text-primary-foreground group-data-[selected]/checkbox:text-primary-foreground",i,a,"group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:text-destructive-foreground",u),children:v("span",{className:"flex items-center justify-center",children:[s.isIndeterminate&&e(F,{className:"size-icon"}),!s.isIndeterminate&&s.isSelected&&e(j,{className:"size-icon"})]})}))})})})}function J({...o}){const t=I({disabled:o.isDisabled});return e(G,{requiredIndicator:t.isRequired,isSelected:t.state.value,isDisabled:t.
|
|
1
|
+
"use client";import{jsx as e,Fragment as k,jsxs as v}from"react/jsx-runtime";import{useId as C}from"react";import{Checkbox as y,composeRenderProps as l,CheckboxGroup as N}from"react-aria-components";import{useFieldContext as I}from"../utilities/form-context.js";import{classNames as r}from"../utilities/theme.js";import{FormField as w,labelVariants as B}from"./form.js";import{IcMinus as F,IcCheck as j}from"./icons.js";import"@tanstack/react-form";import"clsx";import"class-variance-authority";const i="group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50",a="group-data-[invalid]/checkbox:border-destructive",u="focus:outline-none focus-visible:outline-none",b="group-data-[selected]/checkbox:bg-primary",S="relative shrink-0 h-6 w-11 rounded-full border border-input bg-elevation-2 transition-colors duration-200",z="absolute top-1/2 -translate-y-1/2 left-0.5 h-5 w-5 rounded-full bg-background border border-input transition-transform duration-200",D="flex size-input shrink-0 items-center bg-elevation-2 justify-center border border-input text-current ring-offset-background",H=N;function G({className:o,label:t,description:m,errorMessage:h,requiredIndicator:p,variant:x="checkbox",...c}){const g=C(),n=c.id||g,f=x==="switch";return e("div",{className:"group form-field",children:e(w,{label:t,description:m,errorMessage:h,requiredIndicator:p,htmlFor:n,children:e(y,{className:l(o,d=>r("group/checkbox cursor-pointer relative focus-ring flex items-center gap-x-2 disabled-muted",B,d)),id:n,...c,children:l(e(k,{}),(d,s)=>f?e("div",{className:r(S,b,i,a,"group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive",u),children:e("div",{className:r(z,"group-data-[selected]/checkbox:translate-x-4.5",i,a)})}):e("div",{className:r(D,"group-data-[indeterminate]/checkbox:bg-primary",b,"group-data-[indeterminate]/checkbox:text-primary-foreground group-data-[selected]/checkbox:text-primary-foreground",i,a,"group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:text-destructive-foreground",u),children:v("span",{className:"flex items-center justify-center",children:[s.isIndeterminate&&e(F,{className:"size-icon"}),!s.isIndeterminate&&s.isSelected&&e(j,{className:"size-icon"})]})}))})})})}function J({...o}){const t=I({disabled:o.isDisabled});return e(G,{requiredIndicator:t.isRequired,isSelected:t.state.value,isDisabled:t.isSubmitting||o.isDisabled,onChange:()=>t.handleChange(!t.state.value),onBlur:t.handleBlur,...o})}export{G as Checkbox,H as CheckboxGroup,J as TfCheckbox};
|
|
2
2
|
//# sourceMappingURL=checkbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.js","sources":["../../lib/components/checkbox.tsx"],"sourcesContent":["'use client';\nimport { useId } from 'react';\nimport {\n Checkbox as AriaCheckbox,\n CheckboxGroup as AriaCheckboxGroup,\n composeRenderProps,\n type CheckboxProps as AriaCheckboxProps,\n} from 'react-aria-components';\n\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FormField, labelVariants, type FormFieldProps } from './form';\nimport { IcCheck, IcMinus } from './icons';\n\nconst disabledClasses = 'group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50';\nconst invalidBorderClasses = 'group-data-[invalid]/checkbox:border-destructive';\nconst focusResetClasses = 'focus:outline-none focus-visible:outline-none';\nconst selectedPrimaryClasses = 'group-data-[selected]/checkbox:bg-primary';\n\nconst switchBaseClasses =\n 'relative shrink-0 h-6 w-11 rounded-full border border-input bg-elevation-2 transition-colors duration-200';\nconst switchKnobClasses =\n 'absolute top-1/2 -translate-y-1/2 left-0.5 h-5 w-5 rounded-full bg-background border border-input transition-transform duration-200';\n\nconst checkboxBaseClasses =\n 'flex size-input shrink-0 items-center bg-elevation-2 justify-center border border-input text-current ring-offset-background';\n\nexport const CheckboxGroup = AriaCheckboxGroup;\ntype CheckboxProps = AriaCheckboxProps &\n FormFieldProps & {\n variant?: 'checkbox' | 'switch';\n };\nexport function Checkbox({\n className,\n label,\n description,\n errorMessage,\n requiredIndicator,\n variant = 'checkbox',\n ...props\n}: Omit<CheckboxProps, 'children'>) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const isSwitch = variant === 'switch';\n return (\n <div className=\"group form-field\">\n <FormField\n {...{\n label,\n description,\n errorMessage,\n requiredIndicator,\n htmlFor: fieldId,\n }}\n >\n <AriaCheckbox\n className={composeRenderProps(className, className =>\n classNames(\n 'group/checkbox cursor-pointer relative focus-ring flex items-center gap-x-2 disabled-muted',\n labelVariants,\n className\n )\n )}\n id={fieldId}\n {...props}\n >\n {composeRenderProps(<></>, (_, renderProps) => {\n if (isSwitch) {\n return (\n <div\n className={classNames(\n switchBaseClasses,\n selectedPrimaryClasses,\n disabledClasses,\n invalidBorderClasses,\n 'group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive',\n focusResetClasses\n )}\n >\n <div\n className={classNames(\n switchKnobClasses,\n 'group-data-[selected]/checkbox:translate-x-4.5',\n disabledClasses,\n invalidBorderClasses\n )}\n />\n </div>\n );\n }\n\n return (\n <div\n className={classNames(\n checkboxBaseClasses,\n 'group-data-[indeterminate]/checkbox:bg-primary',\n selectedPrimaryClasses,\n 'group-data-[indeterminate]/checkbox:text-primary-foreground group-data-[selected]/checkbox:text-primary-foreground',\n disabledClasses,\n invalidBorderClasses,\n 'group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:text-destructive-foreground',\n focusResetClasses\n )}\n >\n <span className=\"flex items-center justify-center\">\n {renderProps.isIndeterminate && <IcMinus className=\"size-icon\" />}\n {!renderProps.isIndeterminate && renderProps.isSelected && (\n <IcCheck className=\"size-icon\" />\n )}\n </span>\n </div>\n );\n })}\n </AriaCheckbox>\n </FormField>\n </div>\n );\n}\n\nexport type TfCheckboxProps = Omit<React.ComponentProps<typeof Checkbox>, 'onChange' | 'onBlur' | 'isChecked'>;\nexport function TfCheckbox({ ...props }: TfCheckboxProps) {\n const field = useFieldContext<boolean>({ disabled: props.isDisabled });\n return (\n <Checkbox\n requiredIndicator={field.isRequired}\n isSelected={field.state.value}\n isDisabled={field.
|
|
1
|
+
{"version":3,"file":"checkbox.js","sources":["../../lib/components/checkbox.tsx"],"sourcesContent":["'use client';\nimport { useId } from 'react';\nimport {\n Checkbox as AriaCheckbox,\n CheckboxGroup as AriaCheckboxGroup,\n composeRenderProps,\n type CheckboxProps as AriaCheckboxProps,\n} from 'react-aria-components';\n\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FormField, labelVariants, type FormFieldProps } from './form';\nimport { IcCheck, IcMinus } from './icons';\n\nconst disabledClasses = 'group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50';\nconst invalidBorderClasses = 'group-data-[invalid]/checkbox:border-destructive';\nconst focusResetClasses = 'focus:outline-none focus-visible:outline-none';\nconst selectedPrimaryClasses = 'group-data-[selected]/checkbox:bg-primary';\n\nconst switchBaseClasses =\n 'relative shrink-0 h-6 w-11 rounded-full border border-input bg-elevation-2 transition-colors duration-200';\nconst switchKnobClasses =\n 'absolute top-1/2 -translate-y-1/2 left-0.5 h-5 w-5 rounded-full bg-background border border-input transition-transform duration-200';\n\nconst checkboxBaseClasses =\n 'flex size-input shrink-0 items-center bg-elevation-2 justify-center border border-input text-current ring-offset-background';\n\nexport const CheckboxGroup = AriaCheckboxGroup;\ntype CheckboxProps = AriaCheckboxProps &\n FormFieldProps & {\n variant?: 'checkbox' | 'switch';\n };\nexport function Checkbox({\n className,\n label,\n description,\n errorMessage,\n requiredIndicator,\n variant = 'checkbox',\n ...props\n}: Omit<CheckboxProps, 'children'>) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const isSwitch = variant === 'switch';\n return (\n <div className=\"group form-field\">\n <FormField\n {...{\n label,\n description,\n errorMessage,\n requiredIndicator,\n htmlFor: fieldId,\n }}\n >\n <AriaCheckbox\n className={composeRenderProps(className, className =>\n classNames(\n 'group/checkbox cursor-pointer relative focus-ring flex items-center gap-x-2 disabled-muted',\n labelVariants,\n className\n )\n )}\n id={fieldId}\n {...props}\n >\n {composeRenderProps(<></>, (_, renderProps) => {\n if (isSwitch) {\n return (\n <div\n className={classNames(\n switchBaseClasses,\n selectedPrimaryClasses,\n disabledClasses,\n invalidBorderClasses,\n 'group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive',\n focusResetClasses\n )}\n >\n <div\n className={classNames(\n switchKnobClasses,\n 'group-data-[selected]/checkbox:translate-x-4.5',\n disabledClasses,\n invalidBorderClasses\n )}\n />\n </div>\n );\n }\n\n return (\n <div\n className={classNames(\n checkboxBaseClasses,\n 'group-data-[indeterminate]/checkbox:bg-primary',\n selectedPrimaryClasses,\n 'group-data-[indeterminate]/checkbox:text-primary-foreground group-data-[selected]/checkbox:text-primary-foreground',\n disabledClasses,\n invalidBorderClasses,\n 'group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:text-destructive-foreground',\n focusResetClasses\n )}\n >\n <span className=\"flex items-center justify-center\">\n {renderProps.isIndeterminate && <IcMinus className=\"size-icon\" />}\n {!renderProps.isIndeterminate && renderProps.isSelected && (\n <IcCheck className=\"size-icon\" />\n )}\n </span>\n </div>\n );\n })}\n </AriaCheckbox>\n </FormField>\n </div>\n );\n}\n\nexport type TfCheckboxProps = Omit<React.ComponentProps<typeof Checkbox>, 'onChange' | 'onBlur' | 'isChecked'>;\nexport function TfCheckbox({ ...props }: TfCheckboxProps) {\n const field = useFieldContext<boolean>({ disabled: props.isDisabled });\n return (\n <Checkbox\n requiredIndicator={field.isRequired}\n isSelected={field.state.value}\n isDisabled={field.isSubmitting || props.isDisabled}\n onChange={() => field.handleChange(!field.state.value)}\n onBlur={field.handleBlur}\n {...props}\n />\n );\n}\n"],"names":["disabledClasses","invalidBorderClasses","focusResetClasses","selectedPrimaryClasses","switchBaseClasses","switchKnobClasses","checkboxBaseClasses","CheckboxGroup","AriaCheckboxGroup","Checkbox","className","label","description","errorMessage","requiredIndicator","variant","props","generatedId","useId","fieldId","isSwitch","jsx","FormField","AriaCheckbox","composeRenderProps","classNames","labelVariants","Fragment","_","renderProps","jsxs","IcMinus","IcCheck","TfCheckbox","field","useFieldContext"],"mappings":"+eAcA,MAAMA,EAAkB,8FAClBC,EAAuB,mDACvBC,EAAoB,gDACpBC,EAAyB,4CAEzBC,EACF,4GACEC,EACF,sIAEEC,EACF,8HAESC,EAAgBC,EAKtB,SAASC,EAAS,CACrB,UAAAC,EACA,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,QAAAC,EAAU,WACV,GAAGC,CACP,EAAoC,CAChC,MAAMC,EAAcC,EAAA,EACdC,EAAUH,EAAM,IAAMC,EACtBG,EAAWL,IAAY,SAC7B,OACIM,EAAC,MAAA,CAAI,UAAU,mBACX,SAAAA,EAACC,EAAA,CAEO,MAAAX,EACA,YAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,QAASK,EAGb,SAAAE,EAACE,EAAA,CACG,UAAWC,EAAmBd,EAAWA,GACrCe,EACI,6FACAC,EACAhB,CAAA,CACJ,EAEJ,GAAIS,EACH,GAAGH,EAEH,SAAAQ,EAAmBH,EAAAM,EAAA,CAAA,CAAE,EAAK,CAACC,EAAGC,IACvBT,EAEIC,EAAC,MAAA,CACG,UAAWI,EACPrB,EACAD,EACAH,EACAC,EACA,8EACAC,CAAA,EAGJ,SAAAmB,EAAC,MAAA,CACG,UAAWI,EACPpB,EACA,iDACAL,EACAC,CAAA,CACJ,CAAA,CACJ,CAAA,EAMRoB,EAAC,MAAA,CACG,UAAWI,EACPnB,EACA,iDACAH,EACA,qHACAH,EACAC,EACA,uKACAC,CAAA,EAGJ,SAAA4B,EAAC,OAAA,CAAK,UAAU,mCACX,SAAA,CAAAD,EAAY,iBAAmBR,EAACU,EAAA,CAAQ,UAAU,YAAY,EAC9D,CAACF,EAAY,iBAAmBA,EAAY,YACzCR,EAACW,EAAA,CAAQ,UAAU,WAAA,CAAY,CAAA,CAAA,CAEvC,CAAA,CAAA,CAGX,CAAA,CAAA,CACL,CAAA,EAER,CAER,CAGO,SAASC,EAAW,CAAE,GAAGjB,GAA0B,CACtD,MAAMkB,EAAQC,EAAyB,CAAE,SAAUnB,EAAM,WAAY,EACrE,OACIK,EAACZ,EAAA,CACG,kBAAmByB,EAAM,WACzB,WAAYA,EAAM,MAAM,MACxB,WAAYA,EAAM,cAAgBlB,EAAM,WACxC,SAAU,IAAMkB,EAAM,aAAa,CAACA,EAAM,MAAM,KAAK,EACrD,OAAQA,EAAM,WACb,GAAGlB,CAAA,CAAA,CAGhB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsxs as o,jsx as e}from"react/jsx-runtime";import{DatePicker as D,composeRenderProps as c,DateRangePicker as b,Popover as v,Dialog as N}from"react-aria-components";import{parseAbsolute as P,getLocalTimeZone as k}from"@internationalized/date";import{Button as u}from"./button.js";import{Calendar as C,RangeCalendar as R}from"./calendar.js";import{DateInput as m}from"./datefield.js";import{getFieldErrorMessage as d}from"../utilities/form.js";import{useFieldContext as F}from"../utilities/form-context.js";import{classNames as n}from"../utilities/theme.js";import{FormField as f,FieldGroup as g}from"./form.js";import{IcDate as p}from"./icons.js";import"class-variance-authority";import"./loader.js";import"react";import"@tanstack/react-form";import"clsx";const h=({className:a,popoverClassName:r,...i})=>e(v,{className:c(r,t=>n("w-auto p-3 bg-elevation-2 border",t)),children:e(N,{className:n("flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0",a),...i})});function I({label:a,description:r,errorMessage:i,requiredIndicator:t,className:l,...s}){return o(D,{className:c(l,x=>n("group flex flex-col gap-2",x)),...s,children:[e(f,{label:a,description:r,errorMessage:i,requiredIndicator:t,children:o(g,{children:[e(m,{className:"flex-1",variant:"ghost"}),e(u,{variant:"ghost",size:"icon",className:"-me-2 ms-2",children:e(p,{"aria-hidden":!0})})]})}),e(h,{children:e(C,{})})]})}function J({...a}){const r=F({disabled:a.isDisabled});return e(I,{requiredIndicator:r.isRequired,hideTimeZone:!0,isDisabled:a.isDisabled||r.
|
|
1
|
+
"use client";import{jsxs as o,jsx as e}from"react/jsx-runtime";import{DatePicker as D,composeRenderProps as c,DateRangePicker as b,Popover as v,Dialog as N}from"react-aria-components";import{parseAbsolute as P,getLocalTimeZone as k}from"@internationalized/date";import{Button as u}from"./button.js";import{Calendar as C,RangeCalendar as R}from"./calendar.js";import{DateInput as m}from"./datefield.js";import{getFieldErrorMessage as d}from"../utilities/form.js";import{useFieldContext as F}from"../utilities/form-context.js";import{classNames as n}from"../utilities/theme.js";import{FormField as f,FieldGroup as g}from"./form.js";import{IcDate as p}from"./icons.js";import"class-variance-authority";import"./loader.js";import"react";import"@tanstack/react-form";import"clsx";const h=({className:a,popoverClassName:r,...i})=>e(v,{className:c(r,t=>n("w-auto p-3 bg-elevation-2 border",t)),children:e(N,{className:n("flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0",a),...i})});function I({label:a,description:r,errorMessage:i,requiredIndicator:t,className:l,...s}){return o(D,{className:c(l,x=>n("group flex flex-col gap-2",x)),...s,children:[e(f,{label:a,description:r,errorMessage:i,requiredIndicator:t,children:o(g,{children:[e(m,{className:"flex-1",variant:"ghost"}),e(u,{variant:"ghost",size:"icon",className:"-me-2 ms-2",children:e(p,{"aria-hidden":!0})})]})}),e(h,{children:e(C,{})})]})}function J({...a}){const r=F({disabled:a.isDisabled});return e(I,{requiredIndicator:r.isRequired,hideTimeZone:!0,isDisabled:a.isDisabled||r.isSubmitting,value:r.state.value?P(r.state.value,k()):null,onChange:i=>i?r.handleChange(i.toAbsoluteString()):r.handleChange(null),onBlur:r.handleBlur,isInvalid:!!d(r),errorMessage:d(r),...a})}function K({label:a,description:r,errorMessage:i,className:t,...l}){return o(b,{className:c(t,s=>n("group flex flex-col gap-2",s)),...l,children:[e(f,{label:a,errorMessage:i,description:r,children:o(g,{children:[e(m,{variant:"ghost",slot:"start"}),e("span",{"aria-hidden":!0,className:"px-2 body-sm text-muted-foreground",children:"-"}),e(m,{className:"flex-1",variant:"ghost",slot:"end"}),e(u,{variant:"ghost",size:"icon",className:"mr-1 data-[focus-visible]:ring-offset-0",children:e(p,{"aria-hidden":!0})})]})}),e(h,{children:e(R,{})})]})}export{I as DatePicker,K as DateRangePicker,J as TfDatePicker};
|
|
2
2
|
//# sourceMappingURL=date-picker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date-picker.js","sources":["../../lib/components/date-picker.tsx"],"sourcesContent":["'use client';\nimport {\n DatePicker as AriaDatePicker,\n DatePickerProps as AriaDatePickerProps,\n DateRangePicker as AriaDateRangePicker,\n DateRangePickerProps as AriaDateRangePickerProps,\n DateValue as AriaDateValue,\n Dialog as AriaDialog,\n DialogProps as AriaDialogProps,\n PopoverProps as AriaPopoverProps,\n composeRenderProps,\n Popover,\n} from 'react-aria-components';\n\nimport { getLocalTimeZone, parseAbsolute, type ZonedDateTime } from '@internationalized/date';\nimport { Button } from '../components/button';\nimport { Calendar, RangeCalendar } from '../components/calendar';\nimport { DateInput } from '../components/datefield';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcDate } from './icons';\n\n/**\n * Popover container for date picker content.\n *\n * @remarks\n * Provides consistent styling and positioning for the calendar popup.\n */\nconst DatePickerContent = ({\n className,\n popoverClassName,\n ...props\n}: AriaDialogProps & { popoverClassName?: AriaPopoverProps['className'] }) => (\n <Popover\n className={composeRenderProps(popoverClassName, className =>\n classNames('w-auto p-3 bg-elevation-2 border', className)\n )}\n >\n <AriaDialog\n className={classNames(\n 'flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0',\n className\n )}\n {...props}\n />\n </Popover>\n);\n\ninterface DatePickerProps<T extends AriaDateValue> extends AriaDatePickerProps<T>, FormFieldProps {}\n\n/**\n * Date picker component for selecting single dates.\n *\n * @remarks\n * Built with React Aria for accessibility and internationalization support.\n * Supports date validation, min/max values, and custom date formatting.\n *\n * @example\n * ```tsx\n * <DatePicker\n * label=\"Event Date\"\n * isRequired\n * minValue={today(getLocalTimeZone())}\n * />\n * ```\n */\nexport function DatePicker<T extends AriaDateValue>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n className,\n ...props\n}: DatePickerProps<T>) {\n return (\n <AriaDatePicker\n className={composeRenderProps(className, className => classNames('group flex flex-col gap-2', className))}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n <FieldGroup>\n <DateInput className=\"flex-1\" variant=\"ghost\" />\n <Button variant=\"ghost\" size=\"icon\" className={'-me-2 ms-2'}>\n <IcDate aria-hidden />\n </Button>\n </FieldGroup>\n </FormField>\n <DatePickerContent>\n <Calendar />\n </DatePickerContent>\n </AriaDatePicker>\n );\n}\n\n/**\n * Form-integrated date picker that works with TanStack Form.\n *\n * @remarks\n * Automatically handles form state, validation, and error messages.\n * Uses the field context to connect with the form's validation system.\n */\nexport function TfDatePicker({\n ...props\n}: Omit<DatePickerProps<ZonedDateTime>, 'value' | 'onChange' | 'onBlur' | 'isInvalid' | 'errorMessage'>) {\n const field = useFieldContext<string | null>({ disabled: props.isDisabled });\n return (\n <DatePicker\n requiredIndicator={field.isRequired}\n hideTimeZone\n isDisabled={props.isDisabled || field.
|
|
1
|
+
{"version":3,"file":"date-picker.js","sources":["../../lib/components/date-picker.tsx"],"sourcesContent":["'use client';\nimport {\n DatePicker as AriaDatePicker,\n DatePickerProps as AriaDatePickerProps,\n DateRangePicker as AriaDateRangePicker,\n DateRangePickerProps as AriaDateRangePickerProps,\n DateValue as AriaDateValue,\n Dialog as AriaDialog,\n DialogProps as AriaDialogProps,\n PopoverProps as AriaPopoverProps,\n composeRenderProps,\n Popover,\n} from 'react-aria-components';\n\nimport { getLocalTimeZone, parseAbsolute, type ZonedDateTime } from '@internationalized/date';\nimport { Button } from '../components/button';\nimport { Calendar, RangeCalendar } from '../components/calendar';\nimport { DateInput } from '../components/datefield';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcDate } from './icons';\n\n/**\n * Popover container for date picker content.\n *\n * @remarks\n * Provides consistent styling and positioning for the calendar popup.\n */\nconst DatePickerContent = ({\n className,\n popoverClassName,\n ...props\n}: AriaDialogProps & { popoverClassName?: AriaPopoverProps['className'] }) => (\n <Popover\n className={composeRenderProps(popoverClassName, className =>\n classNames('w-auto p-3 bg-elevation-2 border', className)\n )}\n >\n <AriaDialog\n className={classNames(\n 'flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0',\n className\n )}\n {...props}\n />\n </Popover>\n);\n\ninterface DatePickerProps<T extends AriaDateValue> extends AriaDatePickerProps<T>, FormFieldProps {}\n\n/**\n * Date picker component for selecting single dates.\n *\n * @remarks\n * Built with React Aria for accessibility and internationalization support.\n * Supports date validation, min/max values, and custom date formatting.\n *\n * @example\n * ```tsx\n * <DatePicker\n * label=\"Event Date\"\n * isRequired\n * minValue={today(getLocalTimeZone())}\n * />\n * ```\n */\nexport function DatePicker<T extends AriaDateValue>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n className,\n ...props\n}: DatePickerProps<T>) {\n return (\n <AriaDatePicker\n className={composeRenderProps(className, className => classNames('group flex flex-col gap-2', className))}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n <FieldGroup>\n <DateInput className=\"flex-1\" variant=\"ghost\" />\n <Button variant=\"ghost\" size=\"icon\" className={'-me-2 ms-2'}>\n <IcDate aria-hidden />\n </Button>\n </FieldGroup>\n </FormField>\n <DatePickerContent>\n <Calendar />\n </DatePickerContent>\n </AriaDatePicker>\n );\n}\n\n/**\n * Form-integrated date picker that works with TanStack Form.\n *\n * @remarks\n * Automatically handles form state, validation, and error messages.\n * Uses the field context to connect with the form's validation system.\n */\nexport function TfDatePicker({\n ...props\n}: Omit<DatePickerProps<ZonedDateTime>, 'value' | 'onChange' | 'onBlur' | 'isInvalid' | 'errorMessage'>) {\n const field = useFieldContext<string | null>({ disabled: props.isDisabled });\n return (\n <DatePicker\n requiredIndicator={field.isRequired}\n hideTimeZone\n isDisabled={props.isDisabled || field.isSubmitting}\n value={field.state.value ? parseAbsolute(field.state.value, getLocalTimeZone()) : null}\n onChange={v => (v ? field.handleChange(v.toAbsoluteString()) : field.handleChange(null))}\n onBlur={field.handleBlur}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n\ninterface DateRangePickerProps<T extends AriaDateValue> extends AriaDateRangePickerProps<T>, FormFieldProps {}\n\n/**\n * Date range picker component for selecting start and end dates.\n *\n * @remarks\n * Allows users to select a date range with start and end values.\n * Built with React Aria for accessibility and internationalization support.\n * Features separate input fields for start and end dates with range validation.\n *\n * @example\n * ```tsx\n * <DateRangePicker\n * label=\"Booking Period\"\n * description=\"Select your stay dates\"\n * isRequired\n * />\n * ```\n */\nexport function DateRangePicker<T extends AriaDateValue>({\n label,\n description,\n errorMessage,\n className,\n ...props\n}: DateRangePickerProps<T>) {\n return (\n <AriaDateRangePicker\n className={composeRenderProps(className, className => classNames('group flex flex-col gap-2', className))}\n {...props}\n >\n <FormField label={label} errorMessage={errorMessage} description={description}>\n <FieldGroup>\n <DateInput variant=\"ghost\" slot={'start'} />\n <span aria-hidden className=\"px-2 body-sm text-muted-foreground\">\n -\n </span>\n <DateInput className=\"flex-1\" variant=\"ghost\" slot={'end'} />\n <Button variant=\"ghost\" size=\"icon\" className=\"mr-1 data-[focus-visible]:ring-offset-0\">\n <IcDate aria-hidden />\n </Button>\n </FieldGroup>\n </FormField>\n <DatePickerContent>\n <RangeCalendar />\n </DatePickerContent>\n </AriaDateRangePicker>\n );\n}\n"],"names":["DatePickerContent","className","popoverClassName","props","jsx","Popover","composeRenderProps","classNames","AriaDialog","DatePicker","label","description","errorMessage","requiredIndicator","jsxs","AriaDatePicker","FormField","FieldGroup","DateInput","Button","IcDate","Calendar","TfDatePicker","field","useFieldContext","parseAbsolute","getLocalTimeZone","v","getFieldErrorMessage","DateRangePicker","AriaDateRangePicker","RangeCalendar"],"mappings":"uwBA8BA,MAAMA,EAAoB,CAAC,CACvB,UAAAC,EACA,iBAAAC,EACA,GAAGC,CACP,IACIC,EAACC,EAAA,CACG,UAAWC,EAAmBJ,EAAkBD,GAC5CM,EAAW,mCAAoCN,CAAS,CAAA,EAG5D,SAAAG,EAACI,EAAA,CACG,UAAWD,EACP,iFACAN,CAAA,EAEH,GAAGE,CAAA,CAAA,CACR,CACJ,EAqBG,SAASM,EAAoC,CAChD,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,UAAAZ,EACA,GAAGE,CACP,EAAuB,CACnB,OACIW,EAACC,EAAA,CACG,UAAWT,EAAmBL,EAAWA,GAAaM,EAAW,4BAA6BN,CAAS,CAAC,EACvG,GAAGE,EAEJ,SAAA,CAAAC,EAACY,EAAA,CAAgB,MAAAN,EAAO,YAAAC,EAAa,aAAAC,EAAc,kBAAAC,EAC/C,SAAAC,EAACG,EAAA,CACG,SAAA,CAAAb,EAACc,EAAA,CAAU,UAAU,SAAS,QAAQ,QAAQ,EAC9Cd,EAACe,EAAA,CAAO,QAAQ,QAAQ,KAAK,OAAO,UAAW,aAC3C,SAAAf,EAACgB,EAAA,CAAO,cAAW,EAAA,CAAC,CAAA,CACxB,CAAA,CAAA,CACJ,CAAA,CACJ,EACAhB,EAACJ,EAAA,CACG,SAAAI,EAACiB,EAAA,CAAA,CAAS,CAAA,CACd,CAAA,CAAA,CAAA,CAGZ,CASO,SAASC,EAAa,CACzB,GAAGnB,CACP,EAAyG,CACrG,MAAMoB,EAAQC,EAA+B,CAAE,SAAUrB,EAAM,WAAY,EAC3E,OACIC,EAACK,EAAA,CACG,kBAAmBc,EAAM,WACzB,aAAY,GACZ,WAAYpB,EAAM,YAAcoB,EAAM,aACtC,MAAOA,EAAM,MAAM,MAAQE,EAAcF,EAAM,MAAM,MAAOG,EAAA,CAAkB,EAAI,KAClF,SAAUC,GAAMA,EAAIJ,EAAM,aAAaI,EAAE,kBAAkB,EAAIJ,EAAM,aAAa,IAAI,EACtF,OAAQA,EAAM,WACd,UAAW,CAAC,CAACK,EAAqBL,CAAK,EACvC,aAAcK,EAAqBL,CAAK,EACvC,GAAGpB,CAAA,CAAA,CAGhB,CAqBO,SAAS0B,EAAyC,CACrD,MAAAnB,EACA,YAAAC,EACA,aAAAC,EACA,UAAAX,EACA,GAAGE,CACP,EAA4B,CACxB,OACIW,EAACgB,EAAA,CACG,UAAWxB,EAAmBL,EAAWA,GAAaM,EAAW,4BAA6BN,CAAS,CAAC,EACvG,GAAGE,EAEJ,SAAA,CAAAC,EAACY,EAAA,CAAU,MAAAN,EAAc,aAAAE,EAA4B,YAAAD,EACjD,WAACM,EAAA,CACG,SAAA,CAAAb,EAACc,EAAA,CAAU,QAAQ,QAAQ,KAAM,QAAS,IACzC,OAAA,CAAK,cAAW,GAAC,UAAU,qCAAqC,SAAA,IAEjE,IACCA,EAAA,CAAU,UAAU,SAAS,QAAQ,QAAQ,KAAM,MAAO,EAC3Dd,EAACe,EAAA,CAAO,QAAQ,QAAQ,KAAK,OAAO,UAAU,0CAC1C,SAAAf,EAACgB,EAAA,CAAO,cAAW,EAAA,CAAC,CAAA,CACxB,CAAA,CAAA,CACJ,CAAA,CACJ,EACAhB,EAACJ,EAAA,CACG,SAAAI,EAAC2B,EAAA,CAAA,CAAc,CAAA,CACnB,CAAA,CAAA,CAAA,CAGZ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsxs as N,jsx as t}from"react/jsx-runtime";import{useState as D,useMemo as M,useCallback as v}from"react";import{NumberField as z}from"react-aria-components";import{Duration as w}from"../utilities/duration.js";import{getFieldErrorMessage as B}from"../utilities/form.js";import{useFieldContext as $}from"../utilities/form-context.js";import{classNames as b}from"../utilities/theme.js";import{Button as A}from"./button.js";import{FormField as L,FieldGroup as Y}from"./form.js";import{IcLeft as _,IcRight as j}from"./icons.js";import{NumberFieldInput as k}from"./numberfield.js";import"@tanstack/react-form";import"clsx";import"class-variance-authority";import"./loader.js";const q=z,G={years:{full:"Years",short:"yr"},months:{full:"Months",short:"mo"},weeks:{full:"Weeks",short:"wk"},days:{full:"Days",short:"d"},hours:{full:"Hours",short:"hr"},minutes:{full:"Minutes",short:"min"},seconds:{full:"Seconds",short:"sec"}},F=["years","months","days"],H=["hours","minutes","seconds"];function K({id:s,value:r,onChange:e,onBlur:f,label:m,isInvalid:d,isDisabled:h}){return N("div",{className:"flex items-center flex-1 min-w-0 relative",children:[t(q,{"aria-label":m,isInvalid:d,isDisabled:h,value:r,onChange:n=>e(n),onBlur:f,minValue:0,className:"w-full",children:t(k,{id:s,className:"w-full pr-input"})}),t("div",{className:"absolute right-1 select-none text-muted pointer-events-none",children:m})]})}function P({value:s,onChange:r,onBlur:e,label:f,description:m,errorMessage:d,requiredIndicator:h,isDisabled:n,id:S}){const[l,I]=D(!1),c=M(()=>{if(!s||s==="")return{};try{return w.parse(s)}catch{return{}}},[s]),x=v((o,a)=>{const g={...c,[o]:a>0?a:void 0};r(w.serialize(g))},[c,r]),E=()=>{I(o=>!o)},u=!!d,p=S||"duration-field",T=v(o=>{const a=o?[...F,...H]:F,g=o?"short":"full";return a.map((i,y)=>N("div",{className:"contents",children:[t(K,{id:`${p}-${i}`,value:c[i]??0,onChange:C=>x(i,C),onBlur:e||(()=>{}),label:G[i][g],isInvalid:u,isDisabled:n||!1}),y<a.length-1&&t("div",{className:"self-stretch w-px bg-input mx-2 flex-shrink-0","aria-hidden":"true"},`sep-${i}`)]},i))},[p,c,x,e,u,n,l]);return t("div",{className:b("group form-field"),"data-invalid":u?"":void 0,children:t(L,{label:f,description:m,errorMessage:d,requiredIndicator:h,htmlFor:`${p}-years`,children:N("div",{className:"flex-1 flex items-center gap-1",children:[t(Y,{"data-invalid":u?"":void 0,className:"flex flex-row items-stretch w-full overflow-hidden",children:T(l)}),t(A,{type:"button",size:"icon",onPress:E,isDisabled:n,"aria-label":l?"Hide time components":"Show time components","aria-expanded":l,className:b("flex-shrink-0"),children:l?t(_,{className:"size-icon"}):t(j,{className:"size-icon"})})]})})})}function ne({isDisabled:s,...r}){const e=$({disabled:s});return t(P,{requiredIndicator:e.isRequired,value:e.state.value,onChange:e.handleChange,onBlur:e.handleBlur,errorMessage:B(e),isDisabled:s||e.
|
|
1
|
+
"use client";import{jsxs as N,jsx as t}from"react/jsx-runtime";import{useState as D,useMemo as M,useCallback as v}from"react";import{NumberField as z}from"react-aria-components";import{Duration as w}from"../utilities/duration.js";import{getFieldErrorMessage as B}from"../utilities/form.js";import{useFieldContext as $}from"../utilities/form-context.js";import{classNames as b}from"../utilities/theme.js";import{Button as A}from"./button.js";import{FormField as L,FieldGroup as Y}from"./form.js";import{IcLeft as _,IcRight as j}from"./icons.js";import{NumberFieldInput as k}from"./numberfield.js";import"@tanstack/react-form";import"clsx";import"class-variance-authority";import"./loader.js";const q=z,G={years:{full:"Years",short:"yr"},months:{full:"Months",short:"mo"},weeks:{full:"Weeks",short:"wk"},days:{full:"Days",short:"d"},hours:{full:"Hours",short:"hr"},minutes:{full:"Minutes",short:"min"},seconds:{full:"Seconds",short:"sec"}},F=["years","months","days"],H=["hours","minutes","seconds"];function K({id:s,value:r,onChange:e,onBlur:f,label:m,isInvalid:d,isDisabled:h}){return N("div",{className:"flex items-center flex-1 min-w-0 relative",children:[t(q,{"aria-label":m,isInvalid:d,isDisabled:h,value:r,onChange:n=>e(n),onBlur:f,minValue:0,className:"w-full",children:t(k,{id:s,className:"w-full pr-input"})}),t("div",{className:"absolute right-1 select-none text-muted pointer-events-none",children:m})]})}function P({value:s,onChange:r,onBlur:e,label:f,description:m,errorMessage:d,requiredIndicator:h,isDisabled:n,id:S}){const[l,I]=D(!1),c=M(()=>{if(!s||s==="")return{};try{return w.parse(s)}catch{return{}}},[s]),x=v((o,a)=>{const g={...c,[o]:a>0?a:void 0};r(w.serialize(g))},[c,r]),E=()=>{I(o=>!o)},u=!!d,p=S||"duration-field",T=v(o=>{const a=o?[...F,...H]:F,g=o?"short":"full";return a.map((i,y)=>N("div",{className:"contents",children:[t(K,{id:`${p}-${i}`,value:c[i]??0,onChange:C=>x(i,C),onBlur:e||(()=>{}),label:G[i][g],isInvalid:u,isDisabled:n||!1}),y<a.length-1&&t("div",{className:"self-stretch w-px bg-input mx-2 flex-shrink-0","aria-hidden":"true"},`sep-${i}`)]},i))},[p,c,x,e,u,n,l]);return t("div",{className:b("group form-field"),"data-invalid":u?"":void 0,children:t(L,{label:f,description:m,errorMessage:d,requiredIndicator:h,htmlFor:`${p}-years`,children:N("div",{className:"flex-1 flex items-center gap-1",children:[t(Y,{"data-invalid":u?"":void 0,className:"flex flex-row items-stretch w-full overflow-hidden",children:T(l)}),t(A,{type:"button",size:"icon",onPress:E,isDisabled:n,"aria-label":l?"Hide time components":"Show time components","aria-expanded":l,className:b("flex-shrink-0"),children:l?t(_,{className:"size-icon"}):t(j,{className:"size-icon"})})]})})})}function ne({isDisabled:s,...r}){const e=$({disabled:s});return t(P,{requiredIndicator:e.isRequired,value:e.state.value,onChange:e.handleChange,onBlur:e.handleBlur,errorMessage:B(e),isDisabled:s||e.isSubmitting,id:e.name,...r})}export{P as Iso8601DurationField,ne as TfIso8601DurationField};
|
|
2
2
|
//# sourceMappingURL=duration-field.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duration-field.js","sources":["../../lib/components/duration-field.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useMemo, useState } from 'react';\nimport { NumberField as AriaNumberField, NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components';\nimport { Duration } from '../utilities/duration';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { Button } from './button';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcLeft, IcRight } from './icons';\nimport { NumberFieldInput } from './numberfield';\n\nconst ANumberField = AriaNumberField;\n\ntype DurationPartKey = keyof Duration;\n\n/**\n * Segment configurations with both full and short labels\n * https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/date-time-terms\n * https://en.wikipedia.org/wiki/Hour\n */\nconst SEGMENT_LABELS: Record<DurationPartKey, { full: string; short: string }> = {\n years: { full: 'Years', short: 'yr' },\n months: { full: 'Months', short: 'mo' },\n weeks: { full: 'Weeks', short: 'wk' },\n days: { full: 'Days', short: 'd' },\n hours: { full: 'Hours', short: 'hr' },\n minutes: { full: 'Minutes', short: 'min' },\n seconds: { full: 'Seconds', short: 'sec' },\n};\n\nconst DATE_KEYS: DurationPartKey[] = ['years', 'months', 'days'];\nconst TIME_KEYS: DurationPartKey[] = ['hours', 'minutes', 'seconds'];\n\n/**\n * Props for DurationSegment component\n */\ninterface DurationSegmentProps {\n /** Unique identifier for the input field */\n id: string;\n /** Current numeric value */\n value: number;\n /** Callback when value changes */\n onChange: (value: number) => void;\n /** Callback when field loses focus */\n onBlur: () => void;\n /** Display label for the segment */\n label: string;\n /** Whether the field has validation errors */\n isInvalid: boolean;\n /** Whether the field is disabled */\n isDisabled: boolean;\n}\n\nfunction DurationSegment({ id, value, onChange, onBlur, label, isInvalid, isDisabled }: DurationSegmentProps) {\n return (\n <div className=\"flex items-center flex-1 min-w-0 relative\">\n <ANumberField\n aria-label={label}\n isInvalid={isInvalid}\n isDisabled={isDisabled}\n value={value}\n onChange={newValue => onChange(newValue)}\n onBlur={onBlur}\n minValue={0}\n className=\"w-full\"\n >\n <NumberFieldInput id={id} className=\"w-full pr-input\" />\n </ANumberField>\n <div className=\"absolute right-1 select-none text-muted pointer-events-none\">{label}</div>\n </div>\n );\n}\n\ninterface Iso8601DurationFieldBaseProps {\n value: string;\n onChange: (value: string) => void;\n onBlur?: () => void;\n}\n\nexport interface Iso8601DurationFieldProps\n extends Iso8601DurationFieldBaseProps,\n FormFieldProps,\n Omit<AriaNumberFieldProps, 'value' | 'onChange' | 'onBlur'> {\n id?: string;\n}\n\nexport function Iso8601DurationField({\n value,\n onChange,\n onBlur,\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n id,\n}: Iso8601DurationFieldProps) {\n const [showTime, setShowTime] = useState(false);\n\n const duration = useMemo((): Duration => {\n if (!value || value === '') {\n return {};\n }\n try {\n return Duration.parse(value);\n } catch {\n return {};\n }\n }, [value]);\n\n const handlePartChange = useCallback(\n (part: DurationPartKey, partValue: number) => {\n const updatedDuration: Duration = {\n ...duration,\n [part]: partValue > 0 ? partValue : undefined,\n };\n onChange(Duration.serialize(updatedDuration));\n },\n [duration, onChange]\n );\n\n const handleToggleTime = () => {\n setShowTime(prev => !prev);\n };\n\n const isInvalid = !!errorMessage;\n const fieldId = id || 'duration-field';\n\n const renderSegments = useCallback(\n (includeTime: boolean) => {\n const keys = includeTime ? [...DATE_KEYS, ...TIME_KEYS] : DATE_KEYS;\n const labelType = includeTime ? 'short' : 'full';\n\n return keys.map((key, index) => (\n <div key={key} className=\"contents\">\n <DurationSegment\n id={`${fieldId}-${key}`}\n value={duration[key] ?? 0}\n onChange={segmentValue => handlePartChange(key, segmentValue)}\n onBlur={onBlur || (() => {})}\n label={SEGMENT_LABELS[key][labelType]}\n isInvalid={isInvalid}\n isDisabled={isDisabled || false}\n />\n {index < keys.length - 1 && (\n <div\n key={`sep-${key}`}\n className=\"self-stretch w-px bg-input mx-2 flex-shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n ));\n },\n [fieldId, duration, handlePartChange, onBlur, isInvalid, isDisabled, showTime]\n );\n\n return (\n <div className={classNames('group form-field')} data-invalid={isInvalid ? '' : undefined}>\n <FormField\n label={label}\n description={description}\n errorMessage={errorMessage}\n requiredIndicator={requiredIndicator}\n htmlFor={`${fieldId}-years`}\n >\n <div className=\"flex-1 flex items-center gap-1\">\n <FieldGroup\n data-invalid={isInvalid ? '' : undefined}\n className=\"flex flex-row items-stretch w-full overflow-hidden\"\n >\n {renderSegments(showTime)}\n </FieldGroup>\n <Button\n type=\"button\"\n size=\"icon\"\n onPress={handleToggleTime}\n isDisabled={isDisabled}\n aria-label={showTime ? 'Hide time components' : 'Show time components'}\n aria-expanded={showTime}\n className={classNames('flex-shrink-0')}\n >\n {showTime ? <IcLeft className=\"size-icon\" /> : <IcRight className=\"size-icon\" />}\n </Button>\n </div>\n </FormField>\n </div>\n );\n}\n\nexport interface TfIso8601DurationFieldProps extends Omit<Iso8601DurationFieldProps, 'value' | 'onChange'> {}\n\nexport function TfIso8601DurationField({ isDisabled, ...props }: TfIso8601DurationFieldProps) {\n const field = useFieldContext<string>({ disabled: isDisabled });\n\n return (\n <Iso8601DurationField\n requiredIndicator={field.isRequired}\n value={field.state.value}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n isDisabled={isDisabled || field.form.state.isSubmitting}\n id={field.name}\n {...props}\n />\n );\n}\n"],"names":["ANumberField","AriaNumberField","SEGMENT_LABELS","DATE_KEYS","TIME_KEYS","DurationSegment","id","value","onChange","onBlur","label","isInvalid","isDisabled","jsxs","jsx","newValue","NumberFieldInput","Iso8601DurationField","description","errorMessage","requiredIndicator","showTime","setShowTime","useState","duration","useMemo","Duration","handlePartChange","useCallback","part","partValue","updatedDuration","handleToggleTime","prev","fieldId","renderSegments","includeTime","keys","labelType","key","index","segmentValue","classNames","FormField","FieldGroup","Button","IcLeft","IcRight","TfIso8601DurationField","props","field","useFieldContext","getFieldErrorMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"duration-field.js","sources":["../../lib/components/duration-field.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useMemo, useState } from 'react';\nimport { NumberField as AriaNumberField, NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components';\nimport { Duration } from '../utilities/duration';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { Button } from './button';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcLeft, IcRight } from './icons';\nimport { NumberFieldInput } from './numberfield';\n\nconst ANumberField = AriaNumberField;\n\ntype DurationPartKey = keyof Duration;\n\n/**\n * Segment configurations with both full and short labels\n * https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/date-time-terms\n * https://en.wikipedia.org/wiki/Hour\n */\nconst SEGMENT_LABELS: Record<DurationPartKey, { full: string; short: string }> = {\n years: { full: 'Years', short: 'yr' },\n months: { full: 'Months', short: 'mo' },\n weeks: { full: 'Weeks', short: 'wk' },\n days: { full: 'Days', short: 'd' },\n hours: { full: 'Hours', short: 'hr' },\n minutes: { full: 'Minutes', short: 'min' },\n seconds: { full: 'Seconds', short: 'sec' },\n};\n\nconst DATE_KEYS: DurationPartKey[] = ['years', 'months', 'days'];\nconst TIME_KEYS: DurationPartKey[] = ['hours', 'minutes', 'seconds'];\n\n/**\n * Props for DurationSegment component\n */\ninterface DurationSegmentProps {\n /** Unique identifier for the input field */\n id: string;\n /** Current numeric value */\n value: number;\n /** Callback when value changes */\n onChange: (value: number) => void;\n /** Callback when field loses focus */\n onBlur: () => void;\n /** Display label for the segment */\n label: string;\n /** Whether the field has validation errors */\n isInvalid: boolean;\n /** Whether the field is disabled */\n isDisabled: boolean;\n}\n\nfunction DurationSegment({ id, value, onChange, onBlur, label, isInvalid, isDisabled }: DurationSegmentProps) {\n return (\n <div className=\"flex items-center flex-1 min-w-0 relative\">\n <ANumberField\n aria-label={label}\n isInvalid={isInvalid}\n isDisabled={isDisabled}\n value={value}\n onChange={newValue => onChange(newValue)}\n onBlur={onBlur}\n minValue={0}\n className=\"w-full\"\n >\n <NumberFieldInput id={id} className=\"w-full pr-input\" />\n </ANumberField>\n <div className=\"absolute right-1 select-none text-muted pointer-events-none\">{label}</div>\n </div>\n );\n}\n\ninterface Iso8601DurationFieldBaseProps {\n value: string;\n onChange: (value: string) => void;\n onBlur?: () => void;\n}\n\nexport interface Iso8601DurationFieldProps\n extends Iso8601DurationFieldBaseProps,\n FormFieldProps,\n Omit<AriaNumberFieldProps, 'value' | 'onChange' | 'onBlur'> {\n id?: string;\n}\n\nexport function Iso8601DurationField({\n value,\n onChange,\n onBlur,\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n id,\n}: Iso8601DurationFieldProps) {\n const [showTime, setShowTime] = useState(false);\n\n const duration = useMemo((): Duration => {\n if (!value || value === '') {\n return {};\n }\n try {\n return Duration.parse(value);\n } catch {\n return {};\n }\n }, [value]);\n\n const handlePartChange = useCallback(\n (part: DurationPartKey, partValue: number) => {\n const updatedDuration: Duration = {\n ...duration,\n [part]: partValue > 0 ? partValue : undefined,\n };\n onChange(Duration.serialize(updatedDuration));\n },\n [duration, onChange]\n );\n\n const handleToggleTime = () => {\n setShowTime(prev => !prev);\n };\n\n const isInvalid = !!errorMessage;\n const fieldId = id || 'duration-field';\n\n const renderSegments = useCallback(\n (includeTime: boolean) => {\n const keys = includeTime ? [...DATE_KEYS, ...TIME_KEYS] : DATE_KEYS;\n const labelType = includeTime ? 'short' : 'full';\n\n return keys.map((key, index) => (\n <div key={key} className=\"contents\">\n <DurationSegment\n id={`${fieldId}-${key}`}\n value={duration[key] ?? 0}\n onChange={segmentValue => handlePartChange(key, segmentValue)}\n onBlur={onBlur || (() => {})}\n label={SEGMENT_LABELS[key][labelType]}\n isInvalid={isInvalid}\n isDisabled={isDisabled || false}\n />\n {index < keys.length - 1 && (\n <div\n key={`sep-${key}`}\n className=\"self-stretch w-px bg-input mx-2 flex-shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n ));\n },\n [fieldId, duration, handlePartChange, onBlur, isInvalid, isDisabled, showTime]\n );\n\n return (\n <div className={classNames('group form-field')} data-invalid={isInvalid ? '' : undefined}>\n <FormField\n label={label}\n description={description}\n errorMessage={errorMessage}\n requiredIndicator={requiredIndicator}\n htmlFor={`${fieldId}-years`}\n >\n <div className=\"flex-1 flex items-center gap-1\">\n <FieldGroup\n data-invalid={isInvalid ? '' : undefined}\n className=\"flex flex-row items-stretch w-full overflow-hidden\"\n >\n {renderSegments(showTime)}\n </FieldGroup>\n <Button\n type=\"button\"\n size=\"icon\"\n onPress={handleToggleTime}\n isDisabled={isDisabled}\n aria-label={showTime ? 'Hide time components' : 'Show time components'}\n aria-expanded={showTime}\n className={classNames('flex-shrink-0')}\n >\n {showTime ? <IcLeft className=\"size-icon\" /> : <IcRight className=\"size-icon\" />}\n </Button>\n </div>\n </FormField>\n </div>\n );\n}\n\nexport interface TfIso8601DurationFieldProps extends Omit<Iso8601DurationFieldProps, 'value' | 'onChange'> {}\n\nexport function TfIso8601DurationField({ isDisabled, ...props }: TfIso8601DurationFieldProps) {\n const field = useFieldContext<string>({ disabled: isDisabled });\n\n return (\n <Iso8601DurationField\n requiredIndicator={field.isRequired}\n value={field.state.value}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n isDisabled={isDisabled || field.isSubmitting}\n id={field.name}\n {...props}\n />\n );\n}\n"],"names":["ANumberField","AriaNumberField","SEGMENT_LABELS","DATE_KEYS","TIME_KEYS","DurationSegment","id","value","onChange","onBlur","label","isInvalid","isDisabled","jsxs","jsx","newValue","NumberFieldInput","Iso8601DurationField","description","errorMessage","requiredIndicator","showTime","setShowTime","useState","duration","useMemo","Duration","handlePartChange","useCallback","part","partValue","updatedDuration","handleToggleTime","prev","fieldId","renderSegments","includeTime","keys","labelType","key","index","segmentValue","classNames","FormField","FieldGroup","Button","IcLeft","IcRight","TfIso8601DurationField","props","field","useFieldContext","getFieldErrorMessage"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as n,jsxs as C}from"react/jsx-runtime";import{useQuery as w}from"@tanstack/react-query";import{useId as L,useState as K}from"react";import{Select as R,Autocomplete as _}from"react-aria-components";import{Loader as P}from"./loader.js";import{Menu as V,MenuItem as D}from"./menu.js";import{PopoverTrigger as G}from"./popover.js";import{SearchField as Q}from"./searchfield.js";import{useCtxClient as k}from"../utilities/ctx-client.js";import{isEmptyValue as z,getEmptyLabel as F}from"../utilities/empty-option.js";import{getFieldErrorMessage as c}from"../utilities/form.js";import{useFieldContext as M}from"../utilities/form-context.js";import{FormField as H}from"./form.js";import{SelectTrigger as J,SelectPopover as U}from"./select.js";import"../utilities/theme.js";import"clsx";import"./icons.js";import"./list-box.js";import"./button.js";import"class-variance-authority";import"@tanstack/react-form";function W(r){return Array.isArray(r)&&r.every(i=>i&&typeof i=="object"&&"id"in i&&"name"in i)}function N({label:r,description:i,errorMessage:e,requiredIndicator:t,isDisabled:o,isInvalid:
|
|
1
|
+
"use client";import{jsx as n,jsxs as C}from"react/jsx-runtime";import{useQuery as w}from"@tanstack/react-query";import{useId as L,useState as K}from"react";import{Select as R,Autocomplete as _}from"react-aria-components";import{Loader as P}from"./loader.js";import{Menu as V,MenuItem as D}from"./menu.js";import{PopoverTrigger as G}from"./popover.js";import{SearchField as Q}from"./searchfield.js";import{useCtxClient as k}from"../utilities/ctx-client.js";import{isEmptyValue as z,getEmptyLabel as F}from"../utilities/empty-option.js";import{getFieldErrorMessage as c}from"../utilities/form.js";import{useFieldContext as M}from"../utilities/form-context.js";import{FormField as H}from"./form.js";import{SelectTrigger as J,SelectPopover as U}from"./select.js";import"../utilities/theme.js";import"clsx";import"./icons.js";import"./list-box.js";import"./button.js";import"class-variance-authority";import"@tanstack/react-form";function W(r){return Array.isArray(r)&&r.every(i=>i&&typeof i=="object"&&"id"in i&&"name"in i)}function N({label:r,description:i,errorMessage:e,requiredIndicator:t,isDisabled:o,isInvalid:s,onBlur:u,path:a,onChange:m,value:h,renderLabel:q,accessor:f,defaultParams:p,className:x,emptyOption:E,...g}){if(a==="/v3/me")throw Error('Path "/v3/me" is not supported with IdSearch since it is not a searchable resource.');const A=L(),y=g.id||A,B=k(),[S,T]=K(""),{data:I,isError:v,isFetching:b,error:j}=w({queryKey:["get",a],queryFn:async()=>{const d=(await B.GET(a,{params:{query:{search:S,...p?.query},path:{...p?.path}}})).data;return d&&W(d)?d:[]}});return n("div",{className:"group form-field","data-invalid":s?"":void 0,children:n(H,{label:r,description:i,errorMessage:e,requiredIndicator:t,htmlFor:y,children:n(R,{isInvalid:s,children:C(G,{onOpenChange:l=>{l||u?.(h)},children:[n(J,{id:y,isDisabled:o,className:x??"w-full",children:q(h,I,E)}),n(U,{placement:"bottom start",children:C(_,{inputValue:S,onInputChange:T,children:[n(Q,{className:"p-2",autoFocus:!0}),b&&n("div",{className:"p-input",children:n(P,{className:"mx-auto"})}),!b&&!v&&n(V,{...g,className:"max-h-48",items:I,renderEmptyState:()=>n("div",{className:"body-sm p-2",children:"No results found."}),children:l=>n(D,{id:l[f],children:l.name},l[f])}),v&&n("div",{className:"text-destructive p-icon body-sm",children:j.message})]})})]})})})})}function X({...r}){const i=r.value?[r.value]:[];return n(N,{selectedKeys:i,onSelectionChange:e=>{const t=Array.from(e).filter(o=>typeof o=="string")[0];r.onChange(t)},renderLabel:(e,t,o)=>o&&z(e)?F(o):t?.find(s=>s.id===e)?.name??"",selectionMode:"single",...r})}function Y({...r}){const i=r.value;return n(N,{selectedKeys:i,onSelectionChange:e=>{const t=Array.from(e).filter(o=>typeof o=="string");r.onChange(t.length>0?t:[])},selectionMode:"multiple",renderLabel:(e,t,o)=>{if(o&&(!e||e.length===0))return F(o);const u=(e??[]).map(a=>t?.find(m=>m.id===a)?.name??a);return u.length>0?u.join(","):""},...r})}function Se({isDisabled:r,...i}){const e=M({disabled:r});return n(X,{requiredIndicator:e.isRequired,isDisabled:r||e.isSubmitting,value:e.state.value,onBlur:t=>e.handleBlur(),onChange:t=>e.handleChange(t),isInvalid:!!c(e),errorMessage:c(e),...i})}function Ie({isDisabled:r,...i}){const e=M({disabled:r});return n(Y,{requiredIndicator:e.isRequired,isDisabled:r||e.isSubmitting,value:e.state.value,onBlur:t=>e.handleBlur(),onChange:t=>e.handleChange(t),isInvalid:!!c(e),errorMessage:c(e),...i})}export{Y as MultipleIdSearchInput,X as SingleIdSearchInput,Ie as TfMultipleIdSearchInput,Se as TfSingleIdSearchInput};
|
|
2
2
|
//# sourceMappingURL=id-search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id-search.js","sources":["../../lib/components/id-search.tsx"],"sourcesContent":["'use client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useId, useState } from 'react';\nimport { Select as AriaSelect, Autocomplete } from 'react-aria-components';\n\nimport type { ClientPathsWithMethod } from 'openapi-fetch';\nimport { Loader } from '../components/loader';\nimport { Menu, MenuItem } from '../components/menu';\nimport { PopoverTrigger } from '../components/popover';\nimport { SearchField } from '../components/searchfield';\nimport { useCtxClient, type CtxClientType } from '../utilities/ctx-client';\nimport { getEmptyLabel, isEmptyValue, type EmptyOption } from '../utilities/empty-option';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\nimport { SelectPopover, SelectTrigger } from './select';\n\n/**\n * Minimal resource shape used by the ID search inputs.\n * Only `id` and `name` are required.\n *\n * @example\n * const user: BaseSearchableResource = { id: 'u_123', name: 'Nabeel Farooq' };\n */\ntype BaseSearchableResource = {\n /** Unique identifier used as the input value. */\n id: string;\n /** Human-readable label shown to users. */\n name: string;\n};\n\n/**\n * Type guard to check if a value is an array of searchable resources\n */\nfunction isSearchableResourceArray<T extends BaseSearchableResource>(value: unknown): value is T[] {\n return (\n Array.isArray(value) && value.every(item => item && typeof item === 'object' && 'id' in item && 'name' in item)\n );\n}\n\n/**\n * - Generic, accessible ID-search building block.\n * - Search (powered by react-query)\n * - Renders an accessible Autocomplete + Menu listbox\n * - Exposes a controlled `value`/`onChange` contract so callers (and wrappers) can manage state\n *\n * @template T - resource type extending `BaseSearchableResource` (must have `id` and `name`)\n * @template V - controlled value type (e.g. `string` for single-select or `string[]` for multi-select)\n *\n * @param props - props object (see inline property JSDoc for the most important fields)\n *\n * @remarks\n * - Search is automatically handled based on the `resource` prop using the API client from context\n * - When the popover closes, `onBlur` (if provided) is called with the current `value`.\n * - `renderLabel` must convert `value` to a readable string for the control button.\n * - `defaultParams` can be used to pass additional query parameters to the search endpoint\n *\n * @example\n * <BaseIdSearchInput\n * label=\"Owner\"\n * resource=\"user\"\n * value={ownerId}\n * onChange={setOwnerId}\n * renderLabel={(v, data) => data?.find(d => d.id === v)?.name ?? v}\n * />\n *\n * @testing\n * - Ensure API client is provided via context; assert keyboard navigation, open/close behavior, and `onBlur` call on popover close.\n */\nfunction BaseIdSearchInput<T extends BaseSearchableResource, V>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n isInvalid,\n onBlur,\n path,\n onChange,\n value,\n renderLabel,\n accessor,\n defaultParams,\n className,\n emptyOption,\n ...props\n}: FormFieldProps & {\n path: ClientPathsWithMethod<CtxClientType, 'get'>;\n /** Disable interactions. */\n isDisabled?: boolean;\n /** Whether the field is invalid. */\n isInvalid?: boolean;\n /** Key used to access an alternate display accessor on item (kept for compatibility). */\n accessor: keyof BaseSearchableResource;\n /** Controlled value. */\n value: V;\n /** Called when popover closes or the field blurs with the current value. */\n onBlur?: (v: V) => void;\n /** Controlled change handler. */\n onChange: (v: V) => void;\n /** Render a human-readable label for the current value using the latest data. */\n renderLabel: (v: V, data: T[] | undefined, emptyOption?: EmptyOption) => string;\n /** Default parameters to include in the request. This is useful when using /v3/users?role='admin' or /v3/organizations/ID/user-groups */\n defaultParams?: Record<'path' | 'query', any>;\n /** Optional className to customize the trigger button styling. */\n className?: string;\n /* Optional empty option to show when value is empty. */\n emptyOption?: EmptyOption;\n} & Omit<React.ComponentProps<typeof Menu>, 'items' | 'className'>) {\n if (path === '/v3/me') {\n throw Error('Path \"/v3/me\" is not supported with IdSearch since it is not a searchable resource.');\n }\n\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const client = useCtxClient();\n\n const [search, _setSearch] = useState('');\n const { data, isError, isFetching, error } = useQuery({\n // This is the schema that openapi-react-query follows as of 0.5.1\n queryKey: ['get', path],\n queryFn: async (): Promise<T[]> => {\n const result = await client.GET(path, {\n params: {\n query: {\n search,\n ...defaultParams?.query,\n },\n path: {\n ...defaultParams?.path,\n },\n },\n });\n\n // Type narrowing: result.data is inferred as never due to complex union types\n // We use unknown to bypass this and then validate with our type guard\n const responseData: unknown = result.data;\n if (responseData && isSearchableResourceArray<T>(responseData)) {\n return responseData;\n }\n return [];\n },\n });\n\n return (\n <div className=\"group form-field\" data-invalid={isInvalid ? '' : undefined}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <AriaSelect isInvalid={isInvalid}>\n <PopoverTrigger\n onOpenChange={o => {\n if (!o) {\n // searchInputRef.current?.focus();\n onBlur?.(value);\n }\n }}\n >\n <SelectTrigger id={fieldId} isDisabled={isDisabled} className={className ?? 'w-full'}>\n {renderLabel(value, data, emptyOption)}\n </SelectTrigger>\n <SelectPopover placement=\"bottom start\">\n <Autocomplete inputValue={search} onInputChange={_setSearch}>\n <SearchField className={'p-2'} autoFocus />\n {isFetching && (\n <div className=\"p-input\">\n <Loader className=\"mx-auto\" />\n </div>\n )}\n {!isFetching && !isError && (\n <Menu\n {...props}\n className={'max-h-48'}\n items={data}\n renderEmptyState={() => <div className=\"body-sm p-2\">No results found.</div>}\n >\n {item => (\n <MenuItem key={item[accessor]} id={item[accessor]}>\n {item.name}\n </MenuItem>\n )}\n </Menu>\n )}\n {isError && <div className=\"text-destructive p-icon body-sm\">{error.message}</div>}\n </Autocomplete>\n </SelectPopover>\n </PopoverTrigger>\n </AriaSelect>\n </FormField>\n </div>\n );\n}\n\n/**\n * Single-selection ID search input.\n *\n * Thin, typed wrapper around `BaseIdSearchInput` specialized for the very common single-ID case.\n * Adapts the internal selection events into `onChange(id?: string)` and renders the selected label.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <SingleIdSearchInput\n * label=\"Reporter\"\n * value={reporterId}\n * onChange={setReporterId}\n * />\n *\n */\nexport function SingleIdSearchInput<T extends BaseSearchableResource>({\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>,\n 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'\n>) {\n const selectedKeys = props.value ? [props.value] : [];\n\n return (\n <BaseIdSearchInput\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const val = Array.from(e).filter(v => typeof v === 'string')[0];\n props.onChange(val);\n }}\n renderLabel={(v, d, emptyOption) => {\n // If value is empty and emptyOption is set, show the empty label\n if (emptyOption && isEmptyValue(v)) {\n return getEmptyLabel(emptyOption);\n }\n return d?.find(di => di.id === v)?.name ?? '';\n }}\n selectionMode=\"single\"\n {...props}\n />\n );\n}\n\n/**\n * Multi-selection ID search input.\n *\n * Thin wrapper around `BaseIdSearchInput` for the multiple-ID (`string[]`) case.\n * Adapts internal selection events into `onChange(ids: string[])`.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <MultipleIdSearchInput\n * label=\"Reviewers\"\n * value={reviewerIds}\n * onChange={setReviewerIds}\n * />\n *\n * @remarks\n * - The `renderLabel` joins selected item names with commas for compact display.\n */\nexport function MultipleIdSearchInput<T extends BaseSearchableResource>({\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>,\n 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'\n>) {\n const selectedKeys = props.value;\n\n return (\n <BaseIdSearchInput\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const vals = Array.from(e).filter(v => typeof v === 'string');\n props.onChange(vals.length > 0 ? vals : []);\n }}\n selectionMode=\"multiple\"\n renderLabel={(v, d, emptyOption) => {\n // If array is empty and emptyOption is set, show the empty label\n if (emptyOption && (!v || v.length === 0)) {\n return getEmptyLabel(emptyOption);\n }\n\n const values = v ?? [];\n const labels = values.map(vi => {\n return d?.find(di => di.id === vi)?.name ?? vi;\n });\n return labels.length > 0 ? labels.join(',') : '';\n }}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated single-select ID input (field wrapper).\n *\n * Integrates `SingleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfSingleIdSearchInput name=\"ownerId\" label=\"Owner\" />\n \n */\nexport function TfSingleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof SingleIdSearchInput>, 'value' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<string | null>({ disabled: isDisabled });\n return (\n <SingleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.form.state.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated multi-select ID input (field wrapper).\n *\n * Integrates `MultipleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfMultipleIdSearchInput name=\"reviewerIds\" label=\"Reviewers\" />\n *\n */\nexport function TfMultipleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof MultipleIdSearchInput>, 'value' | 'onChange'>) {\n const field = useFieldContext<string[]>({ disabled: isDisabled });\n return (\n <MultipleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.form.state.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n"],"names":["isSearchableResourceArray","value","item","BaseIdSearchInput","label","description","errorMessage","requiredIndicator","isDisabled","isInvalid","onBlur","path","onChange","renderLabel","accessor","defaultParams","className","emptyOption","props","generatedId","useId","fieldId","client","useCtxClient","search","_setSearch","useState","data","isError","isFetching","error","useQuery","responseData","jsx","FormField","AriaSelect","jsxs","PopoverTrigger","o","SelectTrigger","SelectPopover","Autocomplete","SearchField","Loader","Menu","MenuItem","SingleIdSearchInput","selectedKeys","val","v","d","isEmptyValue","getEmptyLabel","di","MultipleIdSearchInput","vals","labels","vi","TfSingleIdSearchInput","field","useFieldContext","_","e","getFieldErrorMessage","TfMultipleIdSearchInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"id-search.js","sources":["../../lib/components/id-search.tsx"],"sourcesContent":["'use client';\nimport { useQuery } from '@tanstack/react-query';\nimport { useId, useState } from 'react';\nimport { Select as AriaSelect, Autocomplete } from 'react-aria-components';\n\nimport type { ClientPathsWithMethod } from 'openapi-fetch';\nimport { Loader } from '../components/loader';\nimport { Menu, MenuItem } from '../components/menu';\nimport { PopoverTrigger } from '../components/popover';\nimport { SearchField } from '../components/searchfield';\nimport { useCtxClient, type CtxClientType } from '../utilities/ctx-client';\nimport { getEmptyLabel, isEmptyValue, type EmptyOption } from '../utilities/empty-option';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\nimport { SelectPopover, SelectTrigger } from './select';\n\n/**\n * Minimal resource shape used by the ID search inputs.\n * Only `id` and `name` are required.\n *\n * @example\n * const user: BaseSearchableResource = { id: 'u_123', name: 'Nabeel Farooq' };\n */\ntype BaseSearchableResource = {\n /** Unique identifier used as the input value. */\n id: string;\n /** Human-readable label shown to users. */\n name: string;\n};\n\n/**\n * Type guard to check if a value is an array of searchable resources\n */\nfunction isSearchableResourceArray<T extends BaseSearchableResource>(value: unknown): value is T[] {\n return (\n Array.isArray(value) && value.every(item => item && typeof item === 'object' && 'id' in item && 'name' in item)\n );\n}\n\n/**\n * - Generic, accessible ID-search building block.\n * - Search (powered by react-query)\n * - Renders an accessible Autocomplete + Menu listbox\n * - Exposes a controlled `value`/`onChange` contract so callers (and wrappers) can manage state\n *\n * @template T - resource type extending `BaseSearchableResource` (must have `id` and `name`)\n * @template V - controlled value type (e.g. `string` for single-select or `string[]` for multi-select)\n *\n * @param props - props object (see inline property JSDoc for the most important fields)\n *\n * @remarks\n * - Search is automatically handled based on the `resource` prop using the API client from context\n * - When the popover closes, `onBlur` (if provided) is called with the current `value`.\n * - `renderLabel` must convert `value` to a readable string for the control button.\n * - `defaultParams` can be used to pass additional query parameters to the search endpoint\n *\n * @example\n * <BaseIdSearchInput\n * label=\"Owner\"\n * resource=\"user\"\n * value={ownerId}\n * onChange={setOwnerId}\n * renderLabel={(v, data) => data?.find(d => d.id === v)?.name ?? v}\n * />\n *\n * @testing\n * - Ensure API client is provided via context; assert keyboard navigation, open/close behavior, and `onBlur` call on popover close.\n */\nfunction BaseIdSearchInput<T extends BaseSearchableResource, V>({\n label,\n description,\n errorMessage,\n requiredIndicator,\n isDisabled,\n isInvalid,\n onBlur,\n path,\n onChange,\n value,\n renderLabel,\n accessor,\n defaultParams,\n className,\n emptyOption,\n ...props\n}: FormFieldProps & {\n path: ClientPathsWithMethod<CtxClientType, 'get'>;\n /** Disable interactions. */\n isDisabled?: boolean;\n /** Whether the field is invalid. */\n isInvalid?: boolean;\n /** Key used to access an alternate display accessor on item (kept for compatibility). */\n accessor: keyof BaseSearchableResource;\n /** Controlled value. */\n value: V;\n /** Called when popover closes or the field blurs with the current value. */\n onBlur?: (v: V) => void;\n /** Controlled change handler. */\n onChange: (v: V) => void;\n /** Render a human-readable label for the current value using the latest data. */\n renderLabel: (v: V, data: T[] | undefined, emptyOption?: EmptyOption) => string;\n /** Default parameters to include in the request. This is useful when using /v3/users?role='admin' or /v3/organizations/ID/user-groups */\n defaultParams?: Record<'path' | 'query', any>;\n /** Optional className to customize the trigger button styling. */\n className?: string;\n /* Optional empty option to show when value is empty. */\n emptyOption?: EmptyOption;\n} & Omit<React.ComponentProps<typeof Menu>, 'items' | 'className'>) {\n if (path === '/v3/me') {\n throw Error('Path \"/v3/me\" is not supported with IdSearch since it is not a searchable resource.');\n }\n\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n const client = useCtxClient();\n\n const [search, _setSearch] = useState('');\n const { data, isError, isFetching, error } = useQuery({\n // This is the schema that openapi-react-query follows as of 0.5.1\n queryKey: ['get', path],\n queryFn: async (): Promise<T[]> => {\n const result = await client.GET(path, {\n params: {\n query: {\n search,\n ...defaultParams?.query,\n },\n path: {\n ...defaultParams?.path,\n },\n },\n });\n\n // Type narrowing: result.data is inferred as never due to complex union types\n // We use unknown to bypass this and then validate with our type guard\n const responseData: unknown = result.data;\n if (responseData && isSearchableResourceArray<T>(responseData)) {\n return responseData;\n }\n return [];\n },\n });\n\n return (\n <div className=\"group form-field\" data-invalid={isInvalid ? '' : undefined}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <AriaSelect isInvalid={isInvalid}>\n <PopoverTrigger\n onOpenChange={o => {\n if (!o) {\n // searchInputRef.current?.focus();\n onBlur?.(value);\n }\n }}\n >\n <SelectTrigger id={fieldId} isDisabled={isDisabled} className={className ?? 'w-full'}>\n {renderLabel(value, data, emptyOption)}\n </SelectTrigger>\n <SelectPopover placement=\"bottom start\">\n <Autocomplete inputValue={search} onInputChange={_setSearch}>\n <SearchField className={'p-2'} autoFocus />\n {isFetching && (\n <div className=\"p-input\">\n <Loader className=\"mx-auto\" />\n </div>\n )}\n {!isFetching && !isError && (\n <Menu\n {...props}\n className={'max-h-48'}\n items={data}\n renderEmptyState={() => <div className=\"body-sm p-2\">No results found.</div>}\n >\n {item => (\n <MenuItem key={item[accessor]} id={item[accessor]}>\n {item.name}\n </MenuItem>\n )}\n </Menu>\n )}\n {isError && <div className=\"text-destructive p-icon body-sm\">{error.message}</div>}\n </Autocomplete>\n </SelectPopover>\n </PopoverTrigger>\n </AriaSelect>\n </FormField>\n </div>\n );\n}\n\n/**\n * Single-selection ID search input.\n *\n * Thin, typed wrapper around `BaseIdSearchInput` specialized for the very common single-ID case.\n * Adapts the internal selection events into `onChange(id?: string)` and renders the selected label.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <SingleIdSearchInput\n * label=\"Reporter\"\n * value={reporterId}\n * onChange={setReporterId}\n * />\n *\n */\nexport function SingleIdSearchInput<T extends BaseSearchableResource>({\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string | null>>,\n 'onSelectionChange' | 'selectionMode' | 'selectedKeys' | 'renderLabel'\n>) {\n const selectedKeys = props.value ? [props.value] : [];\n\n return (\n <BaseIdSearchInput\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const val = Array.from(e).filter(v => typeof v === 'string')[0];\n props.onChange(val);\n }}\n renderLabel={(v, d, emptyOption) => {\n // If value is empty and emptyOption is set, show the empty label\n if (emptyOption && isEmptyValue(v)) {\n return getEmptyLabel(emptyOption);\n }\n return d?.find(di => di.id === v)?.name ?? '';\n }}\n selectionMode=\"single\"\n {...props}\n />\n );\n}\n\n/**\n * Multi-selection ID search input.\n *\n * Thin wrapper around `BaseIdSearchInput` for the multiple-ID (`string[]`) case.\n * Adapts internal selection events into `onChange(ids: string[])`.\n *\n * @template T - resource type (extends BaseSearchableResource)\n *\n * @param props - Inherits `BaseIdSearchInput` props but uses `string[]` value type.\n *\n * @example\n * <MultipleIdSearchInput\n * label=\"Reviewers\"\n * value={reviewerIds}\n * onChange={setReviewerIds}\n * />\n *\n * @remarks\n * - The `renderLabel` joins selected item names with commas for compact display.\n */\nexport function MultipleIdSearchInput<T extends BaseSearchableResource>({\n ...props\n}: Omit<\n React.ComponentProps<typeof BaseIdSearchInput<T, string[]>>,\n 'renderLabel' | 'onSelectionChange' | 'selectionMode' | 'selectedKeys'\n>) {\n const selectedKeys = props.value;\n\n return (\n <BaseIdSearchInput\n selectedKeys={selectedKeys}\n onSelectionChange={e => {\n const vals = Array.from(e).filter(v => typeof v === 'string');\n props.onChange(vals.length > 0 ? vals : []);\n }}\n selectionMode=\"multiple\"\n renderLabel={(v, d, emptyOption) => {\n // If array is empty and emptyOption is set, show the empty label\n if (emptyOption && (!v || v.length === 0)) {\n return getEmptyLabel(emptyOption);\n }\n\n const values = v ?? [];\n const labels = values.map(vi => {\n return d?.find(di => di.id === vi)?.name ?? vi;\n });\n return labels.length > 0 ? labels.join(',') : '';\n }}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated single-select ID input (field wrapper).\n *\n * Integrates `SingleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfSingleIdSearchInput name=\"ownerId\" label=\"Owner\" />\n \n */\nexport function TfSingleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof SingleIdSearchInput>, 'value' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<string | null>({ disabled: isDisabled });\n return (\n <SingleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n\n/**\n * Form-integrated multi-select ID input (field wrapper).\n *\n * Integrates `MultipleIdSearchInput` into the form system using `useFieldContext`.\n * - wires `value`, `onChange`, and `onBlur`\n * - disables the control while the form is submitting\n * - surfaces field-level error messages\n *\n * @example\n * <TfMultipleIdSearchInput name=\"reviewerIds\" label=\"Reviewers\" />\n *\n */\nexport function TfMultipleIdSearchInput({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof MultipleIdSearchInput>, 'value' | 'onChange'>) {\n const field = useFieldContext<string[]>({ disabled: isDisabled });\n return (\n <MultipleIdSearchInput\n requiredIndicator={field.isRequired}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n onBlur={_ => field.handleBlur()}\n onChange={e => field.handleChange(e)}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n"],"names":["isSearchableResourceArray","value","item","BaseIdSearchInput","label","description","errorMessage","requiredIndicator","isDisabled","isInvalid","onBlur","path","onChange","renderLabel","accessor","defaultParams","className","emptyOption","props","generatedId","useId","fieldId","client","useCtxClient","search","_setSearch","useState","data","isError","isFetching","error","useQuery","responseData","jsx","FormField","AriaSelect","jsxs","PopoverTrigger","o","SelectTrigger","SelectPopover","Autocomplete","SearchField","Loader","Menu","MenuItem","SingleIdSearchInput","selectedKeys","val","v","d","isEmptyValue","getEmptyLabel","di","MultipleIdSearchInput","vals","labels","vi","TfSingleIdSearchInput","field","useFieldContext","_","e","getFieldErrorMessage","TfMultipleIdSearchInput"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as r}from"react/jsx-runtime";import{useId as c}from"react";import{EasyMenu as f,MenuItem as p}from"./menu.js";import{getFieldErrorMessage as g}from"../utilities/form.js";import{useFieldContext as b}from"../utilities/form-context.js";import{FormField as h}from"./form.js";import"react-aria-components";import"../utilities/theme.js";import"clsx";import"./icons.js";import"./list-box.js";import"./select.js";import"./button.js";import"class-variance-authority";import"./loader.js";import"./popover.js";import"@tanstack/react-form";function M({items:t,value:e,onChange:o,label:d,errorMessage:s,description:a,requiredIndicator:m,...l}){const u=c(),n=l.id||u;return r("div",{className:"group form-field",children:r(h,{label:d,description:a,errorMessage:s,requiredIndicator:m,htmlFor:n,children:r(f,{id:n,isNonModal:!1,selectionMode:"multiple",selectedKeys:e,onSelectionChange:i=>{typeof i!="string"&&o(i)},items:t,label:l.triggerLabel??r("span",{className:"tabular-nums",children:e.size}),...l,children:i=>r(p,{id:i.id,isDisabled:i?.disabled,children:i.label},i.id)})})})}function L({...t}){const e=b({disabled:t.isDisabled});return r(M,{requiredIndicator:e.isRequired,value:new Set(e.state.value),onChange:o=>e.setValue(Array.from(o)),onClose:e.handleBlur,errorMessage:g(e),...t,isDisabled:t.isDisabled||e.isSubmitting})}export{M as MultiSelect,L as TfMultiSelect};
|
|
2
2
|
//# sourceMappingURL=multi-select.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-select.js","sources":["../../lib/components/multi-select.tsx"],"sourcesContent":["'use client';\nimport React, { useId } from 'react';\nimport { EasyMenu, MenuItem } from '../components/menu';\nimport type { SelectOption } from '../components/select-options';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\ninterface MultipleSelectionProps {\n value: Set<string | number>;\n onChange: (v: Set<string | number>) => void;\n buttonLabel?: React.ReactNode;\n items: SelectOption[];\n}\n\nexport interface MultiSelectProps\n extends MultipleSelectionProps,\n FormFieldProps,\n Omit<React.ComponentProps<typeof EasyMenu>, 'label' | 'items'> {\n triggerLabel?: React.ReactNode;\n}\n\nexport function MultiSelect({\n items,\n value,\n onChange: setValue,\n label,\n errorMessage,\n description,\n requiredIndicator,\n ...props\n}: MultiSelectProps) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n\n return (\n <div className=\"group form-field\">\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <EasyMenu\n id={fieldId}\n isNonModal={false}\n selectionMode=\"multiple\"\n selectedKeys={value}\n onSelectionChange={v => {\n if (typeof v === 'string') return;\n setValue(v);\n }}\n items={items}\n label={props.triggerLabel ?? <span className=\"tabular-nums\">{value.size}</span>}\n {...props}\n >\n {item => (\n <MenuItem id={item.id} key={item.id} isDisabled={item?.disabled}>\n {item.label}\n </MenuItem>\n )}\n </EasyMenu>\n </FormField>\n </div>\n );\n}\n\nexport interface TfMultiSelectProps extends Omit<MultiSelectProps, 'value' | 'onChange'> {}\nexport function TfMultiSelect({ ...props }: TfMultiSelectProps) {\n const field = useFieldContext<string[]>({\n disabled: props.isDisabled,\n });\n\n return (\n <MultiSelect\n requiredIndicator={field.isRequired}\n value={new Set(field.state.value)}\n // @ts-expect-error\n onChange={e => field.setValue(Array.from(e))}\n onClose={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n />\n );\n}\n"],"names":["MultiSelect","items","value","setValue","label","errorMessage","description","requiredIndicator","props","generatedId","useId","fieldId","jsx","FormField","EasyMenu","v","item","MenuItem","TfMultiSelect","field","useFieldContext","e","getFieldErrorMessage"],"mappings":"wiBAqBO,SAASA,EAAY,CACxB,MAAAC,EACA,MAAAC,EACA,SAAUC,EACV,MAAAC,EACA,aAAAC,EACA,YAAAC,EACA,kBAAAC,EACA,GAAGC,CACP,EAAqB,CACjB,MAAMC,EAAcC,EAAA,EACdC,EAAUH,EAAM,IAAMC,EAE5B,OACIG,EAAC,MAAA,CAAI,UAAU,mBACX,WAACC,EAAA,CAAgB,MAAAT,EAAO,YAAAE,EAAa,aAAAD,EAAc,kBAAAE,EAAmB,QAASI,EAC3E,SAAAC,EAACE,EAAA,CACG,GAAIH,EACJ,WAAY,GACZ,cAAc,WACd,aAAcT,EACd,kBAAmBa,GAAK,CAChB,OAAOA,GAAM,UACjBZ,EAASY,CAAC,CACd,EACA,MAAAd,EACA,MAAOO,EAAM,cAAgBI,EAAC,QAAK,UAAU,eAAgB,WAAM,IAAA,CAAK,EACvE,GAAGJ,EAEH,SAAAQ,GACGJ,EAACK,EAAA,CAAS,GAAID,EAAK,GAAkB,WAAYA,GAAM,SAClD,SAAAA,EAAK,KAAA,EADkBA,EAAK,EAEjC,CAAA,CAAA,EAGZ,CAAA,CACJ,CAER,CAGO,SAASE,EAAc,CAAE,GAAGV,GAA6B,CAC5D,MAAMW,EAAQC,EAA0B,CACpC,SAAUZ,EAAM,UAAA,CACnB,EAED,OACII,EAACZ,EAAA,CACG,kBAAmBmB,EAAM,WACzB,MAAO,IAAI,IAAIA,EAAM,MAAM,KAAK,EAEhC,SAAUE,GAAKF,EAAM,SAAS,MAAM,KAAKE,CAAC,CAAC,EAC3C,QAASF,EAAM,WACf,aAAcG,EAAqBH,CAAK,EACvC,GAAGX,
|
|
1
|
+
{"version":3,"file":"multi-select.js","sources":["../../lib/components/multi-select.tsx"],"sourcesContent":["'use client';\nimport React, { useId } from 'react';\nimport { EasyMenu, MenuItem } from '../components/menu';\nimport type { SelectOption } from '../components/select-options';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { FormField, type FormFieldProps } from './form';\ninterface MultipleSelectionProps {\n value: Set<string | number>;\n onChange: (v: Set<string | number>) => void;\n buttonLabel?: React.ReactNode;\n items: SelectOption[];\n}\n\nexport interface MultiSelectProps\n extends MultipleSelectionProps,\n FormFieldProps,\n Omit<React.ComponentProps<typeof EasyMenu>, 'label' | 'items'> {\n triggerLabel?: React.ReactNode;\n}\n\nexport function MultiSelect({\n items,\n value,\n onChange: setValue,\n label,\n errorMessage,\n description,\n requiredIndicator,\n ...props\n}: MultiSelectProps) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n\n return (\n <div className=\"group form-field\">\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <EasyMenu\n id={fieldId}\n isNonModal={false}\n selectionMode=\"multiple\"\n selectedKeys={value}\n onSelectionChange={v => {\n if (typeof v === 'string') return;\n setValue(v);\n }}\n items={items}\n label={props.triggerLabel ?? <span className=\"tabular-nums\">{value.size}</span>}\n {...props}\n >\n {item => (\n <MenuItem id={item.id} key={item.id} isDisabled={item?.disabled}>\n {item.label}\n </MenuItem>\n )}\n </EasyMenu>\n </FormField>\n </div>\n );\n}\n\nexport interface TfMultiSelectProps extends Omit<MultiSelectProps, 'value' | 'onChange'> {}\nexport function TfMultiSelect({ ...props }: TfMultiSelectProps) {\n const field = useFieldContext<string[]>({\n disabled: props.isDisabled,\n });\n\n return (\n <MultiSelect\n requiredIndicator={field.isRequired}\n value={new Set(field.state.value)}\n // @ts-expect-error\n onChange={e => field.setValue(Array.from(e))}\n onClose={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n isDisabled={props.isDisabled || field.isSubmitting}\n />\n );\n}\n"],"names":["MultiSelect","items","value","setValue","label","errorMessage","description","requiredIndicator","props","generatedId","useId","fieldId","jsx","FormField","EasyMenu","v","item","MenuItem","TfMultiSelect","field","useFieldContext","e","getFieldErrorMessage"],"mappings":"wiBAqBO,SAASA,EAAY,CACxB,MAAAC,EACA,MAAAC,EACA,SAAUC,EACV,MAAAC,EACA,aAAAC,EACA,YAAAC,EACA,kBAAAC,EACA,GAAGC,CACP,EAAqB,CACjB,MAAMC,EAAcC,EAAA,EACdC,EAAUH,EAAM,IAAMC,EAE5B,OACIG,EAAC,MAAA,CAAI,UAAU,mBACX,WAACC,EAAA,CAAgB,MAAAT,EAAO,YAAAE,EAAa,aAAAD,EAAc,kBAAAE,EAAmB,QAASI,EAC3E,SAAAC,EAACE,EAAA,CACG,GAAIH,EACJ,WAAY,GACZ,cAAc,WACd,aAAcT,EACd,kBAAmBa,GAAK,CAChB,OAAOA,GAAM,UACjBZ,EAASY,CAAC,CACd,EACA,MAAAd,EACA,MAAOO,EAAM,cAAgBI,EAAC,QAAK,UAAU,eAAgB,WAAM,IAAA,CAAK,EACvE,GAAGJ,EAEH,SAAAQ,GACGJ,EAACK,EAAA,CAAS,GAAID,EAAK,GAAkB,WAAYA,GAAM,SAClD,SAAAA,EAAK,KAAA,EADkBA,EAAK,EAEjC,CAAA,CAAA,EAGZ,CAAA,CACJ,CAER,CAGO,SAASE,EAAc,CAAE,GAAGV,GAA6B,CAC5D,MAAMW,EAAQC,EAA0B,CACpC,SAAUZ,EAAM,UAAA,CACnB,EAED,OACII,EAACZ,EAAA,CACG,kBAAmBmB,EAAM,WACzB,MAAO,IAAI,IAAIA,EAAM,MAAM,KAAK,EAEhC,SAAUE,GAAKF,EAAM,SAAS,MAAM,KAAKE,CAAC,CAAC,EAC3C,QAASF,EAAM,WACf,aAAcG,EAAqBH,CAAK,EACvC,GAAGX,EACJ,WAAYA,EAAM,YAAcW,EAAM,YAAA,CAAA,CAGlD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as r,jsxs as m}from"react/jsx-runtime";import{NumberField as F,composeRenderProps as u,Input as v}from"react-aria-components";import{Button as x}from"./button.js";import{getFieldErrorMessage as d}from"../utilities/form.js";import{useFieldContext as p}from"../utilities/form-context.js";import{classNames as a}from"../utilities/theme.js";import{FormField as f,FieldGroup as h}from"./form.js";import{IcUp as I,IcDown as C}from"./icons.js";import"class-variance-authority";import"./loader.js";import"clsx";import"react";import"@tanstack/react-form";const b=F;function N({className:i,...
|
|
1
|
+
"use client";import{jsx as r,jsxs as m}from"react/jsx-runtime";import{NumberField as F,composeRenderProps as u,Input as v}from"react-aria-components";import{Button as x}from"./button.js";import{getFieldErrorMessage as d}from"../utilities/form.js";import{useFieldContext as p}from"../utilities/form-context.js";import{classNames as a}from"../utilities/theme.js";import{FormField as f,FieldGroup as h}from"./form.js";import{IcUp as I,IcDown as C}from"./icons.js";import"class-variance-authority";import"./loader.js";import"clsx";import"react";import"@tanstack/react-form";const b=F;function N({className:i,...n}){return r(v,{className:u(i,e=>a("w-fit min-w-0 flex-1 border-r border-transparent bg-elevation-2 outline-0 placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden",e)),...n})}function w({className:i,...n}){return m("div",{className:a("absolute right-0 flex h-full flex-col border-l",i),...n,children:[r(c,{slot:"increment",children:r(I,{"aria-hidden":!0,className:"size-icon"})}),r("div",{className:"border-b"}),r(c,{slot:"decrement",children:r(C,{"aria-hidden":!0,className:"size-icon"})})]})}function c({className:i,...n}){return r(x,{className:u(i,e=>a("w-auto grow h-3 px-0.5 text-muted-foreground",e)),variant:"ghost",size:"none",...n})}function D({label:i,description:n,errorMessage:e,requiredIndicator:t,className:o,...l}){return r(b,{className:u(o,s=>a("group form-field",s)),...l,children:r(f,{label:i,description:n,errorMessage:e,requiredIndicator:t,children:m(h,{children:[r(N,{className:"pr-input"}),r(w,{})]})})})}function G({isDisabled:i,...n}){const e=p({disabled:i});return r(D,{isInvalid:!!d(e),isDisabled:i||e.isSubmitting,value:e.state.value,id:e.name,onChange:e.handleChange,onBlur:e.handleBlur,errorMessage:d(e),requiredIndicator:e.isRequired,...n})}function S({label:i,description:n,errorMessage:e,requiredIndicator:t,className:o,...l}){return r(b,{className:u(o,s=>a("group form-field",s)),...l,children:r(f,{label:i,description:n,errorMessage:e,requiredIndicator:t,children:m(h,{children:[r(N,{className:"pr-input"}),r("div",{className:"absolute right-1 select-none text-muted",children:"days"})]})})})}function O({isDisabled:i,...n}){const e=p({disabled:i}),t=86400,o=e.state.value!=null?e.state.value/t:void 0,l=s=>{const g=s*t;e.handleChange(g)};return r(S,{isInvalid:!!d(e),isDisabled:i||e.isSubmitting,value:o,id:e.name,onChange:l,onBlur:e.handleBlur,errorMessage:d(e),requiredIndicator:e.isRequired,...n})}export{S as DaysField,D as NumberField,N as NumberFieldInput,O as TfDaysField,G as TfNumberField};
|
|
2
2
|
//# sourceMappingURL=numberfield.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"numberfield.js","sources":["../../lib/components/numberfield.tsx"],"sourcesContent":["'use client';\nimport {\n ButtonProps as AriaButtonProps,\n Input as AriaInput,\n InputProps as AriaInputProps,\n NumberField as AriaNumberField,\n NumberFieldProps as AriaNumberFieldProps,\n composeRenderProps,\n} from 'react-aria-components';\n\nimport { Button } from '../components/button';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcDown, IcUp } from './icons';\n\nconst ANumberField = AriaNumberField;\n\nexport function NumberFieldInput({ className, ...props }: AriaInputProps) {\n return (\n <AriaInput\n className={composeRenderProps(className, className =>\n classNames(\n 'w-fit min-w-0 flex-1 border-r border-transparent bg-elevation-2 outline-0 placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden',\n className\n )\n )}\n {...props}\n />\n );\n}\n\nfunction NumberFieldSteppers({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div className={classNames('absolute right-0 flex h-full flex-col border-l', className)} {...props}>\n <NumberFieldStepper slot=\"increment\">\n <IcUp aria-hidden className=\"size-icon\" />\n </NumberFieldStepper>\n <div className=\"border-b\" />\n <NumberFieldStepper slot=\"decrement\">\n <IcDown aria-hidden className=\"size-icon\" />\n </NumberFieldStepper>\n </div>\n );\n}\n\nfunction NumberFieldStepper({ className, ...props }: AriaButtonProps) {\n return (\n <Button\n className={composeRenderProps(className, className =>\n classNames('w-auto grow h-3 px-0.5 text-muted-foreground', className)\n )}\n variant={'ghost'}\n size={'none'}\n {...props}\n />\n );\n}\n\nexport type NumberFieldProps = AriaNumberFieldProps & FormFieldProps;\nexport function NumberField({\n label,\n description,\n errorMessage,\n requiredIndicator,\n className,\n ...props\n}: NumberFieldProps) {\n return (\n <ANumberField\n className={composeRenderProps(className, className => classNames('group form-field', className))}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n <FieldGroup>\n <NumberFieldInput className={'pr-input'} />\n <NumberFieldSteppers />\n </FieldGroup>\n </FormField>\n </ANumberField>\n );\n}\n\nexport function TfNumberField({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof NumberField>, 'value' | 'id' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<number>({ disabled: isDisabled });\n\n return (\n <NumberField\n isInvalid={!!getFieldErrorMessage(field)}\n isDisabled={isDisabled || field.
|
|
1
|
+
{"version":3,"file":"numberfield.js","sources":["../../lib/components/numberfield.tsx"],"sourcesContent":["'use client';\nimport {\n ButtonProps as AriaButtonProps,\n Input as AriaInput,\n InputProps as AriaInputProps,\n NumberField as AriaNumberField,\n NumberFieldProps as AriaNumberFieldProps,\n composeRenderProps,\n} from 'react-aria-components';\n\nimport { Button } from '../components/button';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FieldGroup, FormField, type FormFieldProps } from './form';\nimport { IcDown, IcUp } from './icons';\n\nconst ANumberField = AriaNumberField;\n\nexport function NumberFieldInput({ className, ...props }: AriaInputProps) {\n return (\n <AriaInput\n className={composeRenderProps(className, className =>\n classNames(\n 'w-fit min-w-0 flex-1 border-r border-transparent bg-elevation-2 outline-0 placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden',\n className\n )\n )}\n {...props}\n />\n );\n}\n\nfunction NumberFieldSteppers({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div className={classNames('absolute right-0 flex h-full flex-col border-l', className)} {...props}>\n <NumberFieldStepper slot=\"increment\">\n <IcUp aria-hidden className=\"size-icon\" />\n </NumberFieldStepper>\n <div className=\"border-b\" />\n <NumberFieldStepper slot=\"decrement\">\n <IcDown aria-hidden className=\"size-icon\" />\n </NumberFieldStepper>\n </div>\n );\n}\n\nfunction NumberFieldStepper({ className, ...props }: AriaButtonProps) {\n return (\n <Button\n className={composeRenderProps(className, className =>\n classNames('w-auto grow h-3 px-0.5 text-muted-foreground', className)\n )}\n variant={'ghost'}\n size={'none'}\n {...props}\n />\n );\n}\n\nexport type NumberFieldProps = AriaNumberFieldProps & FormFieldProps;\nexport function NumberField({\n label,\n description,\n errorMessage,\n requiredIndicator,\n className,\n ...props\n}: NumberFieldProps) {\n return (\n <ANumberField\n className={composeRenderProps(className, className => classNames('group form-field', className))}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n <FieldGroup>\n <NumberFieldInput className={'pr-input'} />\n <NumberFieldSteppers />\n </FieldGroup>\n </FormField>\n </ANumberField>\n );\n}\n\nexport function TfNumberField({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof NumberField>, 'value' | 'id' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<number>({ disabled: isDisabled });\n\n return (\n <NumberField\n isInvalid={!!getFieldErrorMessage(field)}\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n id={field.name}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n requiredIndicator={field.isRequired}\n {...props}\n />\n );\n}\n\nexport function DaysField({\n label,\n description,\n errorMessage,\n requiredIndicator,\n className,\n ...props\n}: NumberFieldProps) {\n return (\n <ANumberField\n className={composeRenderProps(className, className => classNames('group form-field', className))}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n <FieldGroup>\n <NumberFieldInput className={'pr-input'} />\n <div className=\"absolute right-1 select-none text-muted\">days</div>\n </FieldGroup>\n </FormField>\n </ANumberField>\n );\n}\n\nexport function TfDaysField({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof DaysField>, 'value' | 'id' | 'onChange' | 'onBlur'>) {\n const field = useFieldContext<number>({ disabled: isDisabled });\n\n const SECONDS_PER_DAY = 86400; // 24 * 60 * 60\n\n // Convert seconds to days for display\n const daysValue = field.state.value != null ? field.state.value / SECONDS_PER_DAY : undefined;\n\n // Convert days to seconds when value changes\n const handleDaysChange = (days: number) => {\n const seconds = days * SECONDS_PER_DAY;\n field.handleChange(seconds);\n };\n\n return (\n <DaysField\n isInvalid={!!getFieldErrorMessage(field)}\n isDisabled={isDisabled || field.isSubmitting}\n value={daysValue}\n id={field.name}\n onChange={handleDaysChange}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n requiredIndicator={field.isRequired}\n {...props}\n />\n );\n}\n"],"names":["ANumberField","AriaNumberField","NumberFieldInput","className","props","jsx","AriaInput","composeRenderProps","classNames","NumberFieldSteppers","jsxs","NumberFieldStepper","IcUp","IcDown","Button","NumberField","label","description","errorMessage","requiredIndicator","FormField","FieldGroup","TfNumberField","isDisabled","field","useFieldContext","getFieldErrorMessage","DaysField","TfDaysField","SECONDS_PER_DAY","daysValue","handleDaysChange","days","seconds"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as i,jsxs as a,Fragment as p}from"react/jsx-runtime";import{useId as g}from"react";import{Select as h,composeRenderProps as l,SelectValue as S,ListBox as x}from"react-aria-components";import{Button as N}from"./button.js";import{getFieldErrorMessage as b}from"../utilities/form.js";import{useFieldContext as B}from"../utilities/form-context.js";import{classNames as o}from"../utilities/theme.js";import{FormField as w}from"./form.js";import{IcDown as I}from"./icons.js";import{ListBoxItem as F,ListBoxHeader as v,ListBoxCollection as C}from"./list-box.js";import{Popover as L}from"./popover.js";import"class-variance-authority";import"./loader.js";import"clsx";import"@tanstack/react-form";const D=h,j=F,X=v,Y=C,y=({className:r,...e})=>i(S,{className:l(r,t=>o("line-clamp-1 data-[placeholder]:text-muted-foreground","[&>[slot=description]]:hidden",t)),...e});function P({className:r,children:e,...t}){return i(N,{type:"button",...t,className:o("justify-between px-2",r),children:l(e,n=>a(p,{children:[i("span",{className:"inline-flex gap-1",children:n}),i(I,{"aria-hidden":"true"})]}))})}function V({className:r,...e}){return i(L,{className:l(r,t=>o("w-auto min-w-[--trigger-width]",t)),...e})}function q({className:r,...e}){return i(x,{className:l(r,t=>o("overflow-auto p-1 outline-none",t)),...e})}function H({label:r,description:e,errorMessage:t,children:n,className:d,requiredIndicator:m,items:u,...s}){const f=g(),c=s.id||f;return i("div",{className:o("group form-field",d),children:i(w,{label:r,description:e,errorMessage:t,requiredIndicator:m,htmlFor:c,children:a(D,{...s,children:[i(P,{className:"w-full",id:c,children:i(y,{className:"inline-flex gap-1 items-center"})}),i(V,{children:i(q,{items:u,children:n})})]})})})}function Z({...r}){const e=B({disabled:r.isDisabled});return i(H,{requiredIndicator:e.isRequired,selectedKey:e.state.value,onSelectionChange:t=>e.handleChange(t.toString()),onBlur:e.handleBlur,errorMessage:b(e),...r,isDisabled:r.isDisabled||e.isSubmitting,children:t=>i(j,{id:t.id,children:t.label},t.id)})}export{Y as SelectCollection,X as SelectHeader,j as SelectItem,V as SelectPopover,P as SelectTrigger,y as SelectValue,H as SingleSelect,Z as TfSingleSelect};
|
|
2
2
|
//# sourceMappingURL=select.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","sources":["../../lib/components/select.tsx"],"sourcesContent":["'use client';\nimport { useId } from 'react';\nimport {\n ListBox as AriaListBox,\n ListBoxProps as AriaListBoxProps,\n PopoverProps as AriaPopoverProps,\n Select as AriaSelect,\n SelectProps as AriaSelectProps,\n SelectValue as AriaSelectValue,\n SelectValueProps as AriaSelectValueProps,\n composeRenderProps,\n} from 'react-aria-components';\n\nimport { Button } from '../components/button';\nimport type { SelectOption } from '../components/select-options';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FormField, type FormFieldProps } from './form';\nimport { IcDown } from './icons';\nimport { ListBoxCollection, ListBoxHeader, ListBoxItem } from './list-box';\nimport { Popover } from './popover';\n\nconst ASelect = AriaSelect;\nexport const SelectItem = ListBoxItem;\nexport const SelectHeader = ListBoxHeader;\nexport const SelectCollection = ListBoxCollection;\n\nexport const SelectValue = <T extends object>({ className, ...props }: AriaSelectValueProps<T>) => (\n <AriaSelectValue\n className={composeRenderProps(className, className =>\n classNames(\n 'line-clamp-1 data-[placeholder]:text-muted-foreground',\n /* Description */\n '[&>[slot=description]]:hidden',\n className\n )\n )}\n {...props}\n />\n);\nexport function SelectTrigger({ className, children, ...props }: React.ComponentProps<typeof Button>) {\n return (\n <Button type=\"button\" {...props} className={classNames('justify-between px-2', className)}>\n {composeRenderProps(children, children => (\n <>\n <span className=\"inline-flex gap-1\">{children}</span>\n <IcDown aria-hidden=\"true\" />\n </>\n ))}\n </Button>\n );\n}\n\nexport function SelectPopover({ className, ...props }: AriaPopoverProps) {\n return (\n <Popover\n className={composeRenderProps(className, className =>\n classNames('w-auto min-w-[--trigger-width]', className)\n )}\n {...props}\n />\n );\n}\n\nfunction SelectListBox<T extends object>({ className, ...props }: AriaListBoxProps<T>) {\n return (\n <AriaListBox\n className={composeRenderProps(className, className =>\n classNames('overflow-auto p-1 outline-none', className)\n )}\n {...props}\n />\n );\n}\n\nexport interface SingleSelectProps<T extends SelectOption>\n extends Omit<AriaSelectProps<T>, 'children'>,\n FormFieldProps {\n items: Iterable<T>;\n children: React.ReactNode | ((item: T) => React.ReactNode);\n}\n\nexport function SingleSelect<T extends SelectOption>({\n label,\n description,\n errorMessage,\n children,\n className,\n requiredIndicator,\n items,\n ...props\n}: SingleSelectProps<T>) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n\n return (\n <div className={classNames('group form-field', className)}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <ASelect {...props}>\n <SelectTrigger className={'w-full'} id={fieldId}>\n <SelectValue className={'inline-flex gap-1 items-center'} />\n </SelectTrigger>\n <SelectPopover>\n <SelectListBox items={items}>{children}</SelectListBox>\n </SelectPopover>\n </ASelect>\n </FormField>\n </div>\n );\n}\n\ntype TfSingleSelectProps<T extends SelectOption> = Omit<SingleSelectProps<T>, 'value' | 'setValue' | 'children'>;\n\nexport function TfSingleSelect<T extends SelectOption>({ ...props }: TfSingleSelectProps<T>) {\n const field = useFieldContext<string>({ disabled: props.isDisabled });\n\n return (\n <SingleSelect\n requiredIndicator={field.isRequired}\n selectedKey={field.state.value}\n onSelectionChange={e => field.handleChange(e!.toString())}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n >\n {item => (\n <SelectItem id={item.id} key={item.id}>\n {item.label}\n </SelectItem>\n )}\n </SingleSelect>\n );\n}\n"],"names":["ASelect","AriaSelect","SelectItem","ListBoxItem","SelectHeader","ListBoxHeader","SelectCollection","ListBoxCollection","SelectValue","className","props","jsx","AriaSelectValue","composeRenderProps","classNames","SelectTrigger","children","Button","jsxs","Fragment","IcDown","SelectPopover","Popover","SelectListBox","AriaListBox","SingleSelect","label","description","errorMessage","requiredIndicator","items","generatedId","useId","fieldId","FormField","TfSingleSelect","field","useFieldContext","e","getFieldErrorMessage","item"],"mappings":"ysBAuBA,MAAMA,EAAUC,EACHC,EAAaC,EACbC,EAAeC,EACfC,EAAmBC,EAEnBC,EAAc,CAAmB,CAAE,UAAAC,EAAW,GAAGC,KAC1DC,EAACC,EAAA,CACG,UAAWC,EAAmBJ,EAAWA,GACrCK,EACI,wDAEA,gCACAL,CAAA,CACJ,EAEH,GAAGC,CAAA,CACR,EAEG,SAASK,EAAc,CAAE,UAAAN,EAAW,SAAAO,EAAU,GAAGN,GAA8C,CAClG,OACIC,EAACM,EAAA,CAAO,KAAK,SAAU,GAAGP,EAAO,UAAWI,EAAW,uBAAwBL,CAAS,EACnF,SAAAI,EAAmBG,EAAUA,GAC1BE,EAAAC,EAAA,CACI,SAAA,CAAAR,EAAC,OAAA,CAAK,UAAU,oBAAqB,SAAAK,EAAS,EAC9CL,EAACS,EAAA,CAAO,cAAY,MAAA,CAAO,CAAA,CAAA,CAC/B,CACH,CAAA,CACL,CAER,CAEO,SAASC,EAAc,CAAE,UAAAZ,EAAW,GAAGC,GAA2B,CACrE,OACIC,EAACW,EAAA,CACG,UAAWT,EAAmBJ,EAAWA,GACrCK,EAAW,iCAAkCL,CAAS,CAAA,EAEzD,GAAGC,CAAA,CAAA,CAGhB,CAEA,SAASa,EAAgC,CAAE,UAAAd,EAAW,GAAGC,GAA8B,CACnF,OACIC,EAACa,EAAA,CACG,UAAWX,EAAmBJ,EAAWA,GACrCK,EAAW,iCAAkCL,CAAS,CAAA,EAEzD,GAAGC,CAAA,CAAA,CAGhB,CASO,SAASe,EAAqC,CACjD,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,SAAAZ,EACA,UAAAP,EACA,kBAAAoB,EACA,MAAAC,EACA,GAAGpB,CACP,EAAyB,CACrB,MAAMqB,EAAcC,EAAA,EACdC,EAAUvB,EAAM,IAAMqB,EAE5B,OACIpB,EAAC,OAAI,UAAWG,EAAW,mBAAoBL,CAAS,EACpD,WAACyB,EAAA,CAAgB,MAAAR,EAAO,YAAAC,EAAa,aAAAC,EAAc,kBAAAC,EAAmB,QAASI,EAC3E,SAAAf,EAAClB,EAAA,CAAS,GAAGU,EACT,SAAA,CAAAC,EAACI,EAAA,CAAc,UAAW,SAAU,GAAIkB,EACpC,SAAAtB,EAACH,EAAA,CAAY,UAAW,gCAAA,CAAkC,CAAA,CAC9D,IACCa,EAAA,CACG,SAAAV,EAACY,EAAA,CAAc,MAAAO,EAAe,SAAAd,EAAS,CAAA,CAC3C,CAAA,CAAA,CACJ,EACJ,EACJ,CAER,CAIO,SAASmB,EAAuC,CAAE,GAAGzB,GAAiC,CACzF,MAAM0B,EAAQC,EAAwB,CAAE,SAAU3B,EAAM,WAAY,EAEpE,OACIC,EAACc,EAAA,CACG,kBAAmBW,EAAM,WACzB,YAAaA,EAAM,MAAM,MACzB,kBAAmBE,GAAKF,EAAM,aAAaE,EAAG,UAAU,EACxD,OAAQF,EAAM,WACd,aAAcG,EAAqBH,CAAK,EACvC,GAAG1B,
|
|
1
|
+
{"version":3,"file":"select.js","sources":["../../lib/components/select.tsx"],"sourcesContent":["'use client';\nimport { useId } from 'react';\nimport {\n ListBox as AriaListBox,\n ListBoxProps as AriaListBoxProps,\n PopoverProps as AriaPopoverProps,\n Select as AriaSelect,\n SelectProps as AriaSelectProps,\n SelectValue as AriaSelectValue,\n SelectValueProps as AriaSelectValueProps,\n composeRenderProps,\n} from 'react-aria-components';\n\nimport { Button } from '../components/button';\nimport type { SelectOption } from '../components/select-options';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { FormField, type FormFieldProps } from './form';\nimport { IcDown } from './icons';\nimport { ListBoxCollection, ListBoxHeader, ListBoxItem } from './list-box';\nimport { Popover } from './popover';\n\nconst ASelect = AriaSelect;\nexport const SelectItem = ListBoxItem;\nexport const SelectHeader = ListBoxHeader;\nexport const SelectCollection = ListBoxCollection;\n\nexport const SelectValue = <T extends object>({ className, ...props }: AriaSelectValueProps<T>) => (\n <AriaSelectValue\n className={composeRenderProps(className, className =>\n classNames(\n 'line-clamp-1 data-[placeholder]:text-muted-foreground',\n /* Description */\n '[&>[slot=description]]:hidden',\n className\n )\n )}\n {...props}\n />\n);\nexport function SelectTrigger({ className, children, ...props }: React.ComponentProps<typeof Button>) {\n return (\n <Button type=\"button\" {...props} className={classNames('justify-between px-2', className)}>\n {composeRenderProps(children, children => (\n <>\n <span className=\"inline-flex gap-1\">{children}</span>\n <IcDown aria-hidden=\"true\" />\n </>\n ))}\n </Button>\n );\n}\n\nexport function SelectPopover({ className, ...props }: AriaPopoverProps) {\n return (\n <Popover\n className={composeRenderProps(className, className =>\n classNames('w-auto min-w-[--trigger-width]', className)\n )}\n {...props}\n />\n );\n}\n\nfunction SelectListBox<T extends object>({ className, ...props }: AriaListBoxProps<T>) {\n return (\n <AriaListBox\n className={composeRenderProps(className, className =>\n classNames('overflow-auto p-1 outline-none', className)\n )}\n {...props}\n />\n );\n}\n\nexport interface SingleSelectProps<T extends SelectOption>\n extends Omit<AriaSelectProps<T>, 'children'>,\n FormFieldProps {\n items: Iterable<T>;\n children: React.ReactNode | ((item: T) => React.ReactNode);\n}\n\nexport function SingleSelect<T extends SelectOption>({\n label,\n description,\n errorMessage,\n children,\n className,\n requiredIndicator,\n items,\n ...props\n}: SingleSelectProps<T>) {\n const generatedId = useId();\n const fieldId = props.id || generatedId;\n\n return (\n <div className={classNames('group form-field', className)}>\n <FormField {...{ label, description, errorMessage, requiredIndicator, htmlFor: fieldId }}>\n <ASelect {...props}>\n <SelectTrigger className={'w-full'} id={fieldId}>\n <SelectValue className={'inline-flex gap-1 items-center'} />\n </SelectTrigger>\n <SelectPopover>\n <SelectListBox items={items}>{children}</SelectListBox>\n </SelectPopover>\n </ASelect>\n </FormField>\n </div>\n );\n}\n\ntype TfSingleSelectProps<T extends SelectOption> = Omit<SingleSelectProps<T>, 'value' | 'setValue' | 'children'>;\n\nexport function TfSingleSelect<T extends SelectOption>({ ...props }: TfSingleSelectProps<T>) {\n const field = useFieldContext<string>({ disabled: props.isDisabled });\n\n return (\n <SingleSelect\n requiredIndicator={field.isRequired}\n selectedKey={field.state.value}\n onSelectionChange={e => field.handleChange(e!.toString())}\n onBlur={field.handleBlur}\n errorMessage={getFieldErrorMessage(field)}\n {...props}\n isDisabled={props.isDisabled || field.isSubmitting}\n >\n {item => (\n <SelectItem id={item.id} key={item.id}>\n {item.label}\n </SelectItem>\n )}\n </SingleSelect>\n );\n}\n"],"names":["ASelect","AriaSelect","SelectItem","ListBoxItem","SelectHeader","ListBoxHeader","SelectCollection","ListBoxCollection","SelectValue","className","props","jsx","AriaSelectValue","composeRenderProps","classNames","SelectTrigger","children","Button","jsxs","Fragment","IcDown","SelectPopover","Popover","SelectListBox","AriaListBox","SingleSelect","label","description","errorMessage","requiredIndicator","items","generatedId","useId","fieldId","FormField","TfSingleSelect","field","useFieldContext","e","getFieldErrorMessage","item"],"mappings":"ysBAuBA,MAAMA,EAAUC,EACHC,EAAaC,EACbC,EAAeC,EACfC,EAAmBC,EAEnBC,EAAc,CAAmB,CAAE,UAAAC,EAAW,GAAGC,KAC1DC,EAACC,EAAA,CACG,UAAWC,EAAmBJ,EAAWA,GACrCK,EACI,wDAEA,gCACAL,CAAA,CACJ,EAEH,GAAGC,CAAA,CACR,EAEG,SAASK,EAAc,CAAE,UAAAN,EAAW,SAAAO,EAAU,GAAGN,GAA8C,CAClG,OACIC,EAACM,EAAA,CAAO,KAAK,SAAU,GAAGP,EAAO,UAAWI,EAAW,uBAAwBL,CAAS,EACnF,SAAAI,EAAmBG,EAAUA,GAC1BE,EAAAC,EAAA,CACI,SAAA,CAAAR,EAAC,OAAA,CAAK,UAAU,oBAAqB,SAAAK,EAAS,EAC9CL,EAACS,EAAA,CAAO,cAAY,MAAA,CAAO,CAAA,CAAA,CAC/B,CACH,CAAA,CACL,CAER,CAEO,SAASC,EAAc,CAAE,UAAAZ,EAAW,GAAGC,GAA2B,CACrE,OACIC,EAACW,EAAA,CACG,UAAWT,EAAmBJ,EAAWA,GACrCK,EAAW,iCAAkCL,CAAS,CAAA,EAEzD,GAAGC,CAAA,CAAA,CAGhB,CAEA,SAASa,EAAgC,CAAE,UAAAd,EAAW,GAAGC,GAA8B,CACnF,OACIC,EAACa,EAAA,CACG,UAAWX,EAAmBJ,EAAWA,GACrCK,EAAW,iCAAkCL,CAAS,CAAA,EAEzD,GAAGC,CAAA,CAAA,CAGhB,CASO,SAASe,EAAqC,CACjD,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,SAAAZ,EACA,UAAAP,EACA,kBAAAoB,EACA,MAAAC,EACA,GAAGpB,CACP,EAAyB,CACrB,MAAMqB,EAAcC,EAAA,EACdC,EAAUvB,EAAM,IAAMqB,EAE5B,OACIpB,EAAC,OAAI,UAAWG,EAAW,mBAAoBL,CAAS,EACpD,WAACyB,EAAA,CAAgB,MAAAR,EAAO,YAAAC,EAAa,aAAAC,EAAc,kBAAAC,EAAmB,QAASI,EAC3E,SAAAf,EAAClB,EAAA,CAAS,GAAGU,EACT,SAAA,CAAAC,EAACI,EAAA,CAAc,UAAW,SAAU,GAAIkB,EACpC,SAAAtB,EAACH,EAAA,CAAY,UAAW,gCAAA,CAAkC,CAAA,CAC9D,IACCa,EAAA,CACG,SAAAV,EAACY,EAAA,CAAc,MAAAO,EAAe,SAAAd,EAAS,CAAA,CAC3C,CAAA,CAAA,CACJ,EACJ,EACJ,CAER,CAIO,SAASmB,EAAuC,CAAE,GAAGzB,GAAiC,CACzF,MAAM0B,EAAQC,EAAwB,CAAE,SAAU3B,EAAM,WAAY,EAEpE,OACIC,EAACc,EAAA,CACG,kBAAmBW,EAAM,WACzB,YAAaA,EAAM,MAAM,MACzB,kBAAmBE,GAAKF,EAAM,aAAaE,EAAG,UAAU,EACxD,OAAQF,EAAM,WACd,aAAcG,EAAqBH,CAAK,EACvC,GAAG1B,EACJ,WAAYA,EAAM,YAAc0B,EAAM,aAErC,SAAAI,KACItC,EAAA,CAAW,GAAIsC,EAAK,GAChB,SAAAA,EAAK,KAAA,EADoBA,EAAK,EAEnC,CAAA,CAAA,CAIhB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as r,jsxs as x}from"react/jsx-runtime";import{TextField as b,composeRenderProps as o,TextArea as g,Input as F}from"react-aria-components";import{getFieldErrorMessage as
|
|
1
|
+
"use client";import{jsx as r,jsxs as x}from"react/jsx-runtime";import{TextField as b,composeRenderProps as o,TextArea as g,Input as F}from"react-aria-components";import{getFieldErrorMessage as d}from"../utilities/form.js";import{useFieldContext as T}from"../utilities/form-context.js";import{classNames as l}from"../utilities/theme.js";import{FormField as v,fieldGroupVariants as m}from"./form.js";import{Kbd as N}from"./kbd.js";import"@tanstack/react-form";import"react";import"clsx";import"class-variance-authority";import"./icons.js";const I=b;function A({className:i,kbd:t,...e}){const a=!!t,s=e.disabled;return x("div",{className:"relative",children:[r(F,{className:o(i,n=>l(m(),"file:border-0 file:bg-transparent file:body-sm file:font-medium","disabled-muted","focus-ring",a&&"pr-10",n)),...e}),a&&r("div",{className:"absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none flex items-center","aria-hidden":!0,children:r(N,{value:t,isDisabled:s})})]})}function $({className:i,...t}){return r(g,{className:o(i,e=>l(m(),"h-full min-h-32",e)),...t})}function j({label:i,description:t,errorMessage:e,textArea:a,className:s,inputClassName:n,requiredIndicator:u,kbd:c,isDisabled:f,...p}){return r(I,{className:o(s,h=>l("group form-field",h)),isDisabled:f,...p,children:r(v,{label:i,description:t,errorMessage:e,requiredIndicator:u,children:a?r($,{className:n}):r(A,{className:n,kbd:c})})})}function V({isDisabled:i,...t}){const e=T({disabled:i});return r(j,{isDisabled:i||e.isSubmitting,value:e.state.value,id:e.name,name:e.name,onBlur:e.handleBlur,onChange:e.handleChange,isInvalid:!!d(e),errorMessage:d(e),requiredIndicator:e.isRequired,...t})}export{j as TextField,V as TfTextField};
|
|
2
2
|
//# sourceMappingURL=textfield.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textfield.js","sources":["../../lib/components/textfield.tsx"],"sourcesContent":["'use client';\nimport {\n Input as AriaInput,\n InputProps as AriaInputProps,\n TextArea as AriaTextArea,\n TextAreaProps as AriaTextAreaProps,\n TextField as AriaTextField,\n TextFieldProps as AriaTextFieldProps,\n composeRenderProps,\n} from 'react-aria-components';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { fieldGroupVariants, FormField, type FormFieldProps } from './form';\nimport { Kbd } from './kbd';\n\nconst ATextField = AriaTextField;\n\ninterface InputProps extends AriaInputProps {\n kbd?: string | string[];\n}\n\nfunction Input({ className, kbd, ...props }: InputProps) {\n const hasKbd = !!kbd;\n const isDisabled = props.disabled;\n return (\n <div className=\"relative\">\n <AriaInput\n className={composeRenderProps(className, className =>\n classNames(\n fieldGroupVariants(),\n 'file:border-0 file:bg-transparent file:body-sm file:font-medium',\n /* Disabled */\n 'disabled-muted',\n /* Focused */\n 'focus-ring',\n hasKbd && 'pr-10',\n className\n )\n )}\n {...props}\n />\n\n {hasKbd && (\n <div\n className=\"absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none flex items-center\"\n aria-hidden={true}\n >\n <Kbd value={kbd} isDisabled={isDisabled} />\n </div>\n )}\n </div>\n );\n}\n\nfunction TextArea({ className, ...props }: AriaTextAreaProps) {\n return (\n <AriaTextArea\n className={composeRenderProps(className, className =>\n classNames(fieldGroupVariants(), 'h-full min-h-32', className)\n )}\n {...props}\n />\n );\n}\n\nexport interface TextFieldProps extends AriaTextFieldProps, FormFieldProps {\n textArea?: boolean;\n inputClassName?: string;\n kbd?: string | string[];\n}\n\nexport function TextField({\n label,\n description,\n errorMessage,\n textArea,\n className,\n inputClassName,\n requiredIndicator,\n kbd,\n isDisabled,\n ...props\n}: TextFieldProps) {\n return (\n <ATextField\n className={composeRenderProps(className, className => classNames('group form-field', className))}\n isDisabled={isDisabled}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n {textArea ? <TextArea className={inputClassName} /> : <Input className={inputClassName} kbd={kbd} />}\n </FormField>\n </ATextField>\n );\n}\n\nexport function TfTextField({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof TextField>, 'onBlur' | 'onChange'>) {\n const field = useFieldContext<string>({ disabled: isDisabled });\n\n return (\n <TextField\n isDisabled={isDisabled || field.
|
|
1
|
+
{"version":3,"file":"textfield.js","sources":["../../lib/components/textfield.tsx"],"sourcesContent":["'use client';\nimport {\n Input as AriaInput,\n InputProps as AriaInputProps,\n TextArea as AriaTextArea,\n TextAreaProps as AriaTextAreaProps,\n TextField as AriaTextField,\n TextFieldProps as AriaTextFieldProps,\n composeRenderProps,\n} from 'react-aria-components';\nimport { getFieldErrorMessage } from '../utilities/form';\nimport { useFieldContext } from '../utilities/form-context';\nimport { classNames } from '../utilities/theme';\nimport { fieldGroupVariants, FormField, type FormFieldProps } from './form';\nimport { Kbd } from './kbd';\n\nconst ATextField = AriaTextField;\n\ninterface InputProps extends AriaInputProps {\n kbd?: string | string[];\n}\n\nfunction Input({ className, kbd, ...props }: InputProps) {\n const hasKbd = !!kbd;\n const isDisabled = props.disabled;\n return (\n <div className=\"relative\">\n <AriaInput\n className={composeRenderProps(className, className =>\n classNames(\n fieldGroupVariants(),\n 'file:border-0 file:bg-transparent file:body-sm file:font-medium',\n /* Disabled */\n 'disabled-muted',\n /* Focused */\n 'focus-ring',\n hasKbd && 'pr-10',\n className\n )\n )}\n {...props}\n />\n\n {hasKbd && (\n <div\n className=\"absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none flex items-center\"\n aria-hidden={true}\n >\n <Kbd value={kbd} isDisabled={isDisabled} />\n </div>\n )}\n </div>\n );\n}\n\nfunction TextArea({ className, ...props }: AriaTextAreaProps) {\n return (\n <AriaTextArea\n className={composeRenderProps(className, className =>\n classNames(fieldGroupVariants(), 'h-full min-h-32', className)\n )}\n {...props}\n />\n );\n}\n\nexport interface TextFieldProps extends AriaTextFieldProps, FormFieldProps {\n textArea?: boolean;\n inputClassName?: string;\n kbd?: string | string[];\n}\n\nexport function TextField({\n label,\n description,\n errorMessage,\n textArea,\n className,\n inputClassName,\n requiredIndicator,\n kbd,\n isDisabled,\n ...props\n}: TextFieldProps) {\n return (\n <ATextField\n className={composeRenderProps(className, className => classNames('group form-field', className))}\n isDisabled={isDisabled}\n {...props}\n >\n <FormField {...{ label, description, errorMessage, requiredIndicator }}>\n {textArea ? <TextArea className={inputClassName} /> : <Input className={inputClassName} kbd={kbd} />}\n </FormField>\n </ATextField>\n );\n}\n\nexport function TfTextField({\n isDisabled,\n ...props\n}: Omit<React.ComponentProps<typeof TextField>, 'onBlur' | 'onChange'>) {\n const field = useFieldContext<string>({ disabled: isDisabled });\n\n return (\n <TextField\n isDisabled={isDisabled || field.isSubmitting}\n value={field.state.value}\n id={field.name}\n name={field.name}\n onBlur={field.handleBlur}\n onChange={field.handleChange}\n isInvalid={!!getFieldErrorMessage(field)}\n errorMessage={getFieldErrorMessage(field)}\n requiredIndicator={field.isRequired}\n {...props}\n />\n );\n}\n"],"names":["ATextField","AriaTextField","Input","className","kbd","props","hasKbd","isDisabled","jsxs","jsx","AriaInput","composeRenderProps","classNames","fieldGroupVariants","Kbd","TextArea","AriaTextArea","TextField","label","description","errorMessage","textArea","inputClassName","requiredIndicator","FormField","TfTextField","field","useFieldContext","getFieldErrorMessage"],"mappings":"yhBAgBA,MAAMA,EAAaC,EAMnB,SAASC,EAAM,CAAE,UAAAC,EAAW,IAAAC,EAAK,GAAGC,GAAqB,CACrD,MAAMC,EAAS,CAAC,CAACF,EACXG,EAAaF,EAAM,SACzB,OACIG,EAAC,MAAA,CAAI,UAAU,WACX,SAAA,CAAAC,EAACC,EAAA,CACG,UAAWC,EAAmBR,EAAWA,GACrCS,EACIC,EAAA,EACA,kEAEA,iBAEA,aACAP,GAAU,QACVH,CAAA,CACJ,EAEH,GAAGE,CAAA,CAAA,EAGPC,GACGG,EAAC,MAAA,CACG,UAAU,kFACV,cAAa,GAEb,SAAAA,EAACK,EAAA,CAAI,MAAOV,EAAK,WAAAG,CAAA,CAAwB,CAAA,CAAA,CAC7C,EAER,CAER,CAEA,SAASQ,EAAS,CAAE,UAAAZ,EAAW,GAAGE,GAA4B,CAC1D,OACII,EAACO,EAAA,CACG,UAAWL,EAAmBR,EAAWA,GACrCS,EAAWC,EAAA,EAAsB,kBAAmBV,CAAS,CAAA,EAEhE,GAAGE,CAAA,CAAA,CAGhB,CAQO,SAASY,EAAU,CACtB,MAAAC,EACA,YAAAC,EACA,aAAAC,EACA,SAAAC,EACA,UAAAlB,EACA,eAAAmB,EACA,kBAAAC,EACA,IAAAnB,EACA,WAAAG,EACA,GAAGF,CACP,EAAmB,CACf,OACII,EAACT,EAAA,CACG,UAAWW,EAAmBR,EAAWA,GAAaS,EAAW,mBAAoBT,CAAS,CAAC,EAC/F,WAAAI,EACC,GAAGF,EAEJ,SAAAI,EAACe,GAAgB,MAAAN,EAAO,YAAAC,EAAa,aAAAC,EAAc,kBAAAG,EAC9C,SAAAF,IAAYN,EAAA,CAAS,UAAWO,EAAgB,EAAKb,EAACP,GAAM,UAAWoB,EAAgB,IAAAlB,EAAU,CAAA,CACtG,CAAA,CAAA,CAGZ,CAEO,SAASqB,EAAY,CACxB,WAAAlB,EACA,GAAGF,CACP,EAAwE,CACpE,MAAMqB,EAAQC,EAAwB,CAAE,SAAUpB,EAAY,EAE9D,OACIE,EAACQ,EAAA,CACG,WAAYV,GAAcmB,EAAM,aAChC,MAAOA,EAAM,MAAM,MACnB,GAAIA,EAAM,KACV,KAAMA,EAAM,KACZ,OAAQA,EAAM,WACd,SAAUA,EAAM,aAChB,UAAW,CAAC,CAACE,EAAqBF,CAAK,EACvC,aAAcE,EAAqBF,CAAK,EACxC,kBAAmBA,EAAM,WACxB,GAAGrB,CAAA,CAAA,CAGhB"}
|
|
@@ -23,4 +23,5 @@ export declare function useFieldContext<T>({ disabled }: {
|
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
}): import('@tanstack/react-form').FieldApi<any, string, T, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any> & {
|
|
25
25
|
isRequired: boolean;
|
|
26
|
+
isSubmitting: boolean;
|
|
26
27
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createFormHookContexts as
|
|
1
|
+
import{createFormHookContexts as a,useStore as u}from"@tanstack/react-form";import{useEffect as l}from"react";const{fieldContext:m,formContext:x,useFieldContext:f}=a();function C({disabled:e}){const o=f(),i=u(o.form.store,t=>t.isSubmitting);l(()=>{o.setMeta(t=>({...t,disabled:!!e}))},[e,o]);const s=o.options?.validators?.onBlur||o.options?.validators?.onChange||o.options?.validators?.onMount,r=!!s&&!(t=>{if(!t||typeof t!="object"||typeof t.safeParse!="function")return!1;const n=t;return n.safeParse(void 0).success||n.safeParse(null).success})(s);return Object.assign(o,{isRequired:r,isSubmitting:i})}export{m as fieldContext,x as formContext,C as useFieldContext};
|
|
2
2
|
//# sourceMappingURL=form-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-context.js","sources":["../../lib/utilities/form-context.tsx"],"sourcesContent":["import { createFormHookContexts } from '@tanstack/react-form';\nimport { useEffect } from 'react';\n\ntype ZodLikeSchema = {\n safeParse: (input: unknown) => { success: boolean };\n};\n\n/**\n * Exports contexts and hooks used by all form-related field components.\n *\n * These contexts come from @tanstack/react-form's createFormHookContexts helper\n * and provide a lightweight, strongly-typed way for nested field components\n * (text inputs, selects, checkboxes, etc.) to access the current field\n * and form instances.\n *\n * Usage example:\n * ```ts\n * import { useFieldContext } from './form-context';\n * const field = useFieldContext<MyFieldType>();\n * ```\n */\nconst { fieldContext, formContext, useFieldContext: _useFieldContext } = createFormHookContexts();\n\nexport { fieldContext, formContext };\n/**\n * Custom hook to handle disabled state for form fields\n * @param {boolean} disabled - The disabled prop passed to the component\n * @returns The field context with disabled state properly managed\n */\nexport function useFieldContext<T>({ disabled }: { disabled?: boolean }) {\n const field = _useFieldContext<T>();\n\n useEffect(() => {\n field.setMeta(meta => ({\n ...meta,\n disabled: !!disabled,\n }));\n }, [disabled, field]);\n\n // Detect if field is required based on validators\n const validator =\n field.options?.validators?.onBlur || field.options?.validators?.onChange || field.options?.validators?.onMount;\n\n // Check if the validator allows missing values (undefined/null)\n const allowsMissingValue = (schema: unknown): boolean => {\n // Type guard: ensure it's a Zod-like schema with safeParse method\n if (!schema || typeof schema !== 'object' || typeof (schema as any).safeParse !== 'function') {\n return false;\n }\n\n const zodSchema = schema as ZodLikeSchema;\n\n // Check if undefined or null are valid inputs\n return zodSchema.safeParse(undefined).success || zodSchema.safeParse(null).success;\n };\n\n const isRequired = !!validator && !allowsMissingValue(validator);\n\n return Object.assign(field, { isRequired });\n}\n"],"names":["fieldContext","formContext","_useFieldContext","createFormHookContexts","useFieldContext","disabled","field","useEffect","meta","validator","isRequired","schema","zodSchema"],"mappings":"
|
|
1
|
+
{"version":3,"file":"form-context.js","sources":["../../lib/utilities/form-context.tsx"],"sourcesContent":["import { createFormHookContexts, useStore } from '@tanstack/react-form';\nimport { useEffect } from 'react';\n\ntype ZodLikeSchema = {\n safeParse: (input: unknown) => { success: boolean };\n};\n\n/**\n * Exports contexts and hooks used by all form-related field components.\n *\n * These contexts come from @tanstack/react-form's createFormHookContexts helper\n * and provide a lightweight, strongly-typed way for nested field components\n * (text inputs, selects, checkboxes, etc.) to access the current field\n * and form instances.\n *\n * Usage example:\n * ```ts\n * import { useFieldContext } from './form-context';\n * const field = useFieldContext<MyFieldType>();\n * ```\n */\nconst { fieldContext, formContext, useFieldContext: _useFieldContext } = createFormHookContexts();\n\nexport { fieldContext, formContext };\n/**\n * Custom hook to handle disabled state for form fields\n * @param {boolean} disabled - The disabled prop passed to the component\n * @returns The field context with disabled state properly managed\n */\nexport function useFieldContext<T>({ disabled }: { disabled?: boolean }) {\n const field = _useFieldContext<T>();\n\n // https://github.com/TanStack/form/issues/1705\n // https://tanstack.com/form/latest/docs/framework/react/guides/reactivity\n const isSubmitting = useStore(field.form.store, state => state.isSubmitting);\n\n useEffect(() => {\n field.setMeta(meta => ({\n ...meta,\n disabled: !!disabled,\n }));\n }, [disabled, field]);\n\n // Detect if field is required based on validators\n const validator =\n field.options?.validators?.onBlur || field.options?.validators?.onChange || field.options?.validators?.onMount;\n\n // Check if the validator allows missing values (undefined/null)\n const allowsMissingValue = (schema: unknown): boolean => {\n // Type guard: ensure it's a Zod-like schema with safeParse method\n if (!schema || typeof schema !== 'object' || typeof (schema as any).safeParse !== 'function') {\n return false;\n }\n\n const zodSchema = schema as ZodLikeSchema;\n\n // Check if undefined or null are valid inputs\n return zodSchema.safeParse(undefined).success || zodSchema.safeParse(null).success;\n };\n\n const isRequired = !!validator && !allowsMissingValue(validator);\n\n return Object.assign(field, { isRequired, isSubmitting });\n}\n"],"names":["fieldContext","formContext","_useFieldContext","createFormHookContexts","useFieldContext","disabled","field","isSubmitting","useStore","state","useEffect","meta","validator","isRequired","schema","zodSchema"],"mappings":"8GAqBA,KAAM,CAAE,aAAAA,EAAc,YAAAC,EAAa,gBAAiBC,CAAA,EAAqBC,EAAA,EAQlE,SAASC,EAAmB,CAAE,SAAAC,GAAoC,CACrE,MAAMC,EAAQJ,EAAA,EAIRK,EAAeC,EAASF,EAAM,KAAK,MAAOG,GAASA,EAAM,YAAY,EAE3EC,EAAU,IAAM,CACZJ,EAAM,QAAQK,IAAS,CACnB,GAAGA,EACH,SAAU,CAAC,CAACN,CAAA,EACd,CACN,EAAG,CAACA,EAAUC,CAAK,CAAC,EAGpB,MAAMM,EACFN,EAAM,SAAS,YAAY,QAAUA,EAAM,SAAS,YAAY,UAAYA,EAAM,SAAS,YAAY,QAerGO,EAAa,CAAC,CAACD,GAAa,EAZNE,GAA6B,CAErD,GAAI,CAACA,GAAU,OAAOA,GAAW,UAAY,OAAQA,EAAe,WAAc,WAC9E,MAAO,GAGX,MAAMC,EAAYD,EAGlB,OAAOC,EAAU,UAAU,MAAS,EAAE,SAAWA,EAAU,UAAU,IAAI,EAAE,OAC/E,GAEsDH,CAAS,EAE/D,OAAO,OAAO,OAAON,EAAO,CAAE,WAAAO,EAAY,aAAAN,EAAc,CAC5D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptlex/web-components",
|
|
3
|
-
"version": "6.6.6-
|
|
3
|
+
"version": "6.6.6-alpha69",
|
|
4
4
|
"description": "React component library for Cryptlex web applications",
|
|
5
5
|
"author": "Cryptlex",
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"*.{ts,tsx,css,scss,json}": "prettier --write"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@cryptlex/web-api-types": "2.
|
|
51
|
+
"@cryptlex/web-api-types": "2.112.0",
|
|
52
52
|
"@dnd-kit/core": "6.3.1",
|
|
53
53
|
"@dnd-kit/sortable": "10.0.0",
|
|
54
54
|
"@dnd-kit/utilities": "3.2.2",
|