@ahrowe/ui 0.31.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/esm/common/actionButtons/actionButtons.mjs +1 -1
  2. package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
  3. package/dist/esm/common/alert/alert.mjs +1 -1
  4. package/dist/esm/common/alert/alert.mjs.map +1 -1
  5. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  6. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  7. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  8. package/dist/esm/common/card/Card.mjs +1 -1
  9. package/dist/esm/common/card/Card.mjs.map +1 -1
  10. package/dist/esm/common/card/card.types.mjs.map +1 -1
  11. package/dist/esm/common/carousel/carousel.mjs +1 -1
  12. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  13. package/dist/esm/common/chip/chip.mjs +1 -1
  14. package/dist/esm/common/chip/chip.mjs.map +1 -1
  15. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  16. package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
  17. package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
  18. package/dist/esm/common/configProvider/useLabels.mjs +2 -0
  19. package/dist/esm/common/configProvider/useLabels.mjs.map +1 -0
  20. package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
  21. package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
  22. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
  23. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  24. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  25. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  26. package/dist/esm/common/drawer/drawer.mjs +1 -1
  27. package/dist/esm/common/drawer/drawer.mjs.map +1 -1
  28. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  29. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  30. package/dist/esm/common/emptyState/emptyState.mjs +1 -1
  31. package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
  32. package/dist/esm/common/fab/components/fabBase/fabBase.mjs +1 -1
  33. package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
  34. package/dist/esm/common/fab/fab.mjs +1 -1
  35. package/dist/esm/common/fab/fab.mjs.map +1 -1
  36. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +1 -1
  37. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -1
  38. package/dist/esm/common/input/input.mjs +1 -1
  39. package/dist/esm/common/input/input.mjs.map +1 -1
  40. package/dist/esm/common/input/input.types.mjs.map +1 -1
  41. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  42. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  43. package/dist/esm/common/modal/modal.mjs +1 -1
  44. package/dist/esm/common/modal/modal.mjs.map +1 -1
  45. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  46. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  47. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  48. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  49. package/dist/esm/common/otpInput/otpInput.mjs +1 -1
  50. package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
  51. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  52. package/dist/esm/common/pagination/pagination.mjs +1 -1
  53. package/dist/esm/common/pagination/pagination.mjs.map +1 -1
  54. package/dist/esm/common/progressBar/progressBar.mjs +1 -1
  55. package/dist/esm/common/progressBar/progressBar.mjs.map +1 -1
  56. package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
  57. package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
  58. package/dist/esm/common/searchInput/searchInput.mjs +1 -1
  59. package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
  60. package/dist/esm/common/splitButton/splitButton.mjs +1 -1
  61. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
  62. package/dist/esm/common/timer/timer.mjs +1 -1
  63. package/dist/esm/common/timer/timer.mjs.map +1 -1
  64. package/dist/esm/common/toast/toast.mjs +1 -1
  65. package/dist/esm/common/toast/toast.mjs.map +1 -1
  66. package/dist/esm/common/toast/toastProvider.mjs +1 -1
  67. package/dist/esm/common/toast/toastProvider.mjs.map +1 -1
  68. package/dist/esm/common/tree/tree.mjs +1 -1
  69. package/dist/esm/common/tree/tree.mjs.map +1 -1
  70. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  71. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  72. package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
  73. package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
  74. package/dist/esm/index.mjs +1 -1
  75. package/dist/index.cjs +3 -3
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/types/common/actionButtons/actionButtons.types.d.ts +9 -2
  78. package/dist/types/common/alert/alert.types.d.ts +7 -0
  79. package/dist/types/common/breadcrumb/breadcrumb.types.d.ts +7 -0
  80. package/dist/types/common/card/card.types.d.ts +6 -1
  81. package/dist/types/common/carousel/carousel.types.d.ts +13 -0
  82. package/dist/types/common/chip/chip.types.d.ts +13 -2
  83. package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
  84. package/dist/types/common/colorPicker/colorPicker.types.d.ts +13 -1
  85. package/dist/types/common/configProvider/configProvider.types.d.ts +26 -1
  86. package/dist/types/common/configProvider/index.d.ts +1 -0
  87. package/dist/types/common/configProvider/useLabels.d.ts +22 -0
  88. package/dist/types/common/confirmModal/confirmModal.types.d.ts +13 -4
  89. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +2 -14
  90. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +23 -0
  91. package/dist/types/common/datePicker/datePicker.d.ts +1 -22
  92. package/dist/types/common/datePicker/datePicker.types.d.ts +60 -0
  93. package/dist/types/common/datePicker/index.d.ts +1 -0
  94. package/dist/types/common/drawer/drawer.d.ts +1 -1
  95. package/dist/types/common/drawer/drawer.types.d.ts +7 -1
  96. package/dist/types/common/dropdown/dropdown.types.d.ts +6 -6
  97. package/dist/types/common/emptyState/emptyState.d.ts +1 -1
  98. package/dist/types/common/emptyState/emptyState.types.d.ts +13 -1
  99. package/dist/types/common/fab/components/fabBase/fabBase.d.ts +1 -1
  100. package/dist/types/common/fab/components/fabBase/fabBase.types.d.ts +3 -1
  101. package/dist/types/common/fab/fab.d.ts +1 -1
  102. package/dist/types/common/fab/fab.types.d.ts +6 -1
  103. package/dist/types/common/infiniteBlock/infiniteBlock.d.ts +1 -1
  104. package/dist/types/common/infiniteBlock/infiniteBlock.types.d.ts +2 -0
  105. package/dist/types/common/input/input.types.d.ts +13 -0
  106. package/dist/types/common/klipyPicker/klipyPicker.d.ts +1 -1
  107. package/dist/types/common/klipyPicker/klipyPicker.types.d.ts +7 -0
  108. package/dist/types/common/modal/modal.types.d.ts +7 -0
  109. package/dist/types/common/multiSelect/multiSelect.types.d.ts +13 -6
  110. package/dist/types/common/numberInput/numberInput.types.d.ts +15 -2
  111. package/dist/types/common/otpInput/otpInput.types.d.ts +9 -0
  112. package/dist/types/common/pagination/pagination.types.d.ts +15 -0
  113. package/dist/types/common/progressBar/progressBar.d.ts +1 -1
  114. package/dist/types/common/progressBar/progressBar.types.d.ts +6 -1
  115. package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +6 -0
  116. package/dist/types/common/searchInput/searchInput.d.ts +1 -1
  117. package/dist/types/common/searchInput/searchInput.types.d.ts +13 -1
  118. package/dist/types/common/splitButton/splitButton.types.d.ts +7 -0
  119. package/dist/types/common/timer/timer.types.d.ts +7 -0
  120. package/dist/types/common/toast/toast.d.ts +4 -2
  121. package/dist/types/common/toast/toast.types.d.ts +11 -1
  122. package/dist/types/common/toast/toastProvider.d.ts +1 -1
  123. package/dist/types/common/tree/tree.types.d.ts +7 -2
  124. package/dist/types/common/virtualList/virtualList.types.d.ts +15 -6
  125. package/dist/types/common/virtualList/virtualListHeader.d.ts +3 -3
  126. package/docs/ActionButtons.md +7 -6
  127. package/docs/Alert.md +2 -0
  128. package/docs/Breadcrumb.md +2 -0
  129. package/docs/Card.md +2 -0
  130. package/docs/Carousel.md +2 -0
  131. package/docs/Chip.md +5 -1
  132. package/docs/ColorPicker.md +4 -0
  133. package/docs/ConfigProvider.md +23 -0
  134. package/docs/ConfirmModal.md +7 -5
  135. package/docs/DatePicker.md +6 -1
  136. package/docs/Drawer.md +2 -0
  137. package/docs/Dropdown.md +2 -0
  138. package/docs/EmptyState.md +4 -0
  139. package/docs/Fab.md +2 -0
  140. package/docs/FormValidatorGroup.md +1 -1
  141. package/docs/Input.md +2 -0
  142. package/docs/KlipyPicker.md +2 -0
  143. package/docs/Modal.md +2 -0
  144. package/docs/MultiSelect.md +7 -5
  145. package/docs/NumberInput.md +8 -2
  146. package/docs/OtpInput.md +2 -0
  147. package/docs/Pagination.md +2 -0
  148. package/docs/ProgressBar.md +2 -0
  149. package/docs/RoomDrawer.md +2 -0
  150. package/docs/SearchInput.md +4 -0
  151. package/docs/SplitButton.md +2 -0
  152. package/docs/Timer.md +2 -0
  153. package/docs/Toast.md +2 -0
  154. package/docs/Tree.md +3 -1
  155. package/docs/VirtualList.md +3 -2
  156. package/docs/Wizard.md +1 -2
  157. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{InputType as e}from"../input/input.types.mjs";import t from"../input/input.mjs";import n from"./searchInput.module.mjs";import{useEffect as r,useRef as i}from"react";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s({value:s,onChange:c,onDebounce:l,placeholder:u,label:d,debounceMs:f=500,totalAmount:p,showAmount:m=!0,className:h,width:g,..._}){let v=i(null);r(()=>()=>{v.current!==null&&clearTimeout(v.current)},[]);function y(e){let t=e==null?``:String(e),n=t.trim()===``?``:t;c(n),v.current!==null&&clearTimeout(v.current),v.current=setTimeout(()=>{l?.(n)},f)}let b=m&&typeof p==`number`&&!Number.isNaN(p);return o(`div`,{..._,className:h,style:g==null?void 0:{width:g},children:[a(t,{autoComplete:`off`,type:e.Search,label:d,placeholder:u,value:s,onChange:y}),b&&o(`p`,{className:n.resultCount,children:[p,` `,p===1?`result`:`results`]})]})}export{s as default};
1
+ import{useLabels as e}from"../configProvider/useLabels.mjs";import{InputType as t}from"../input/input.types.mjs";import n from"../input/input.mjs";import r from"./searchInput.module.mjs";import{useEffect as i,useRef as a}from"react";import o from"classnames";import{jsx as s,jsxs as c}from"react/jsx-runtime";var l={results:e=>`${e} ${e===1?`result`:`results`}`};function u({value:u,onChange:d,onDebounce:f,placeholder:p,label:m,debounceMs:h=500,totalAmount:g,showAmount:_=!0,className:v,width:y,style:b,classNames:x,styles:S,labels:C,...w}){let T=e(`SearchInput`,C,l),E=a(null);i(()=>()=>{E.current!==null&&clearTimeout(E.current)},[]);function D(e){let t=e==null?``:String(e),n=t.trim()===``?``:t;d(n),E.current!==null&&clearTimeout(E.current),E.current=setTimeout(()=>{f?.(n)},h)}let O=_&&typeof g==`number`&&!Number.isNaN(g);return c(`div`,{...w,className:o(v,x?.root),style:{...y==null?void 0:{width:y},...b,...S?.root},children:[s(n,{autoComplete:`off`,className:x?.input,style:S?.input,type:t.Search,label:m,placeholder:p,value:u,onChange:D}),O&&s(`p`,{className:o(r.resultCount,x?.resultCount),style:S?.resultCount,children:T.results(g)})]})}export{u as default};
2
2
  //# sourceMappingURL=searchInput.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"searchInput.mjs","names":[],"sources":["../../../../package/common/searchInput/searchInput.tsx"],"sourcesContent":["import { useEffect, useRef, type ReactElement } from 'react';\nimport Input from 'components/common/input';\nimport { InputType } from 'components/common/input/input.types';\nimport styles from './searchInput.module.pcss';\nimport type { SearchInputProps } from './searchInput.types';\n\nexport default function SearchInput({\n value,\n onChange,\n onDebounce,\n placeholder,\n label,\n debounceMs = 500,\n totalAmount,\n showAmount = true,\n className,\n width,\n ...rest\n}: SearchInputProps): ReactElement {\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n },\n [],\n );\n\n function handleChange(val: unknown) {\n const str = val != null ? String(val) : '';\n const trimmed = str.trim() === '' ? '' : str;\n onChange(trimmed);\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => {\n onDebounce?.(trimmed);\n }, debounceMs);\n }\n\n const showCount = showAmount && typeof totalAmount === 'number' && !Number.isNaN(totalAmount);\n\n return (\n <div {...rest} className={className} style={width != null ? { width } : undefined}>\n <Input\n autoComplete='off'\n type={InputType.Search}\n label={label}\n placeholder={placeholder}\n value={value}\n onChange={handleChange}\n />\n {showCount && (\n <p className={styles.resultCount}>\n {totalAmount} {totalAmount === 1 ? 'result' : 'results'}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"+NAMA,SAAwB,EAAY,CAClC,QACA,WACA,aACA,cACA,QACA,aAAa,IACb,cACA,aAAa,GACb,YACA,QACA,GAAG,GAC8B,CACjC,IAAM,EAAW,EAA6C,IAAI,EAElE,UACc,CACN,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAC9D,EACA,CAAC,CACH,EAEA,SAAS,EAAa,EAAc,CAClC,IAAM,EAAM,GAAO,KAAqB,GAAd,OAAO,CAAG,EAC9B,EAAU,EAAI,KAAK,IAAM,GAAK,GAAK,EACzC,EAAS,CAAO,EACZ,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,CAClC,IAAa,CAAO,CACtB,EAAG,CAAU,CACf,CAEA,IAAM,EAAY,GAAc,OAAO,GAAgB,UAAY,CAAC,OAAO,MAAM,CAAW,EAE5F,OACE,EAAC,MAAD,CAAK,GAAI,EAAiB,YAAW,MAAO,GAAS,KAAmB,IAAA,GAAZ,CAAE,OAAM,EAApE,SAAA,CACE,EAAC,EAAD,CACE,aAAa,MACb,KAAM,EAAU,OACT,QACM,cACN,QACP,SAAU,CACX,CAAA,EACA,GACC,EAAC,IAAD,CAAG,UAAW,EAAO,YAArB,SAAA,CACG,EAAY,IAAE,IAAgB,EAAI,SAAW,SAC7C,CAEF,CAAA,CAAA,GAET"}
1
+ {"version":3,"file":"searchInput.mjs","names":[],"sources":["../../../../package/common/searchInput/searchInput.tsx"],"sourcesContent":["import { useEffect, useRef, type ReactElement } from 'react';\nimport cx from 'classnames';\nimport Input from 'components/common/input';\nimport { InputType } from 'components/common/input/input.types';\nimport styles from './searchInput.module.pcss';\nimport { useLabels } from '../configProvider';\nimport type { SearchInputLabels, SearchInputProps } from './searchInput.types';\n\nconst DEFAULT_LABELS: Required<SearchInputLabels> = {\n results: (count) => `${count} ${count === 1 ? 'result' : 'results'}`,\n};\n\nexport default function SearchInput({\n value,\n onChange,\n onDebounce,\n placeholder,\n label,\n debounceMs = 500,\n totalAmount,\n showAmount = true,\n className,\n width,\n style,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n}: SearchInputProps): ReactElement {\n const text = useLabels('SearchInput', labels, DEFAULT_LABELS);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n },\n [],\n );\n\n function handleChange(val: unknown) {\n const str = val != null ? String(val) : '';\n const trimmed = str.trim() === '' ? '' : str;\n onChange(trimmed);\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => {\n onDebounce?.(trimmed);\n }, debounceMs);\n }\n\n const showCount = showAmount && typeof totalAmount === 'number' && !Number.isNaN(totalAmount);\n\n return (\n <div\n {...rest}\n className={cx(className, classNames?.root)}\n style={{ ...(width != null ? { width } : undefined), ...style, ...slotStyles?.root }}\n >\n <Input\n autoComplete='off'\n className={classNames?.input}\n style={slotStyles?.input}\n type={InputType.Search}\n label={label}\n placeholder={placeholder}\n value={value}\n onChange={handleChange}\n />\n {showCount && (\n <p className={cx(styles.resultCount, classNames?.resultCount)} style={slotStyles?.resultCount}>\n {text.results(totalAmount)}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"qTAQA,IAAM,EAA8C,CAClD,QAAU,GAAU,GAAG,EAAM,GAAG,IAAU,EAAI,SAAW,WAC3D,EAEA,SAAwB,EAAY,CAClC,QACA,WACA,aACA,cACA,QACA,aAAa,IACb,cACA,aAAa,GACb,YACA,QACA,QACA,aACA,OAAQ,EACR,SACA,GAAG,GAC8B,CACjC,IAAM,EAAO,EAAU,cAAe,EAAQ,CAAc,EACtD,EAAW,EAA6C,IAAI,EAElE,UACc,CACN,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAC9D,EACA,CAAC,CACH,EAEA,SAAS,EAAa,EAAc,CAClC,IAAM,EAAM,GAAO,KAAqB,GAAd,OAAO,CAAG,EAC9B,EAAU,EAAI,KAAK,IAAM,GAAK,GAAK,EACzC,EAAS,CAAO,EACZ,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,CAClC,IAAa,CAAO,CACtB,EAAG,CAAU,CACf,CAEA,IAAM,EAAY,GAAc,OAAO,GAAgB,UAAY,CAAC,OAAO,MAAM,CAAW,EAE5F,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAW,GAAY,IAAI,EACzC,MAAO,CAAE,GAAI,GAAS,KAAmB,IAAA,GAAZ,CAAE,OAAM,EAAgB,GAAG,EAAO,GAAG,GAAY,IAAK,EAHrF,SAAA,CAKE,EAAC,EAAD,CACE,aAAa,MACb,UAAW,GAAY,MACvB,MAAO,GAAY,MACnB,KAAM,EAAU,OACT,QACM,cACN,QACP,SAAU,CACX,CAAA,EACA,GACC,EAAC,IAAD,CAAG,UAAW,EAAG,EAAO,YAAa,GAAY,WAAW,EAAG,MAAO,GAAY,YAC/E,SAAA,EAAK,QAAQ,CAAW,CACxB,CAAA,CAEF,GAET"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{ButtonSize as t,ButtonStyleType as n}from"../button/button.types.mjs";import{renderIcon as r}from"../utils/renderIcon.mjs";import i from"../button/button.mjs";import a from"../interactableDiv/index.mjs";import{Align as o}from"../floatingMenu/floatingMenu.types.mjs";import s from"../floatingMenu/floatingMenu.mjs";import c from"../buttonGroup/buttonGroup.mjs";import l from"./splitButton.module.mjs";import{useEffect as u,useRef as d,useState as f}from"react";import p from"classnames";import{faChevronDown as m}from"@fortawesome/free-solid-svg-icons";import{jsx as h,jsxs as g}from"react/jsx-runtime";function _(e,t){return(e%t+t)%t}function v(v){let{children:y,onClick:b=()=>{},actions:x=[],styleType:S=n.Primary,size:C=t.Default,disabled:w=!1,isLoading:T=!1,align:E=o.Right,className:D,style:O,classNames:k,styles:A,...j}=e(`SplitButton`,v),[M,N]=f(!1),P=d([]),[F,I]=f(w);w!==F&&(I(w),w&&N(!1)),u(()=>{if(!M)return;let e=x.findIndex(e=>!e.disabled);e!==-1&&P.current[e]?.focus()},[M]);function L(e,t){let n=x.map((e,t)=>t).filter(e=>!x[e].disabled);if(n.length===0)return;let r=n.indexOf(e),i=r===-1?t===1?0:n.length-1:_(r+t,n.length);P.current[n[i]]?.focus()}function R(e){let t=P.current.findIndex(e=>e===document.activeElement);e.key===`ArrowDown`?(e.preventDefault(),L(t,1)):e.key===`ArrowUp`?(e.preventDefault(),L(t,-1)):e.key===`Home`?(e.preventDefault(),L(-1,1)):e.key===`End`&&(e.preventDefault(),L(-1,-1))}return g(c,{...j,className:p(l.splitButton,k?.root,D),style:{...O,...A?.root},children:[h(i,{styleType:S,size:C,disabled:w,isLoading:T,onClick:b,className:p(l.splitButtonPrimary,k?.primaryButton),style:A?.primaryButton,children:y}),h(s,{isOpen:M,onOpenChange:N,align:E,dontCloseOnChildClick:!0,content:h(`ul`,{className:p(l.splitButtonMenu,k?.menu),style:A?.menu,role:`menu`,onKeyDown:R,children:x.map((e,t)=>h(`li`,{role:`none`,children:g(a,{ref:e=>{P.current[t]=e},role:`menuitem`,tabIndex:e.disabled?-1:0,"aria-disabled":e.disabled,className:p(l.splitButtonMenuItem,{[l.splitButtonMenuItemDisabled]:e.disabled},k?.menuItem),style:A?.menuItem,onClick:()=>{w||e.disabled||(e.onClick(),N(!1))},children:[e.icon?r(e.icon,{className:l.splitButtonMenuItemIcon}):null,e.label]})},e.id))}),children:h(i,{styleType:S,size:C,disabled:w,icon:m,"aria-label":`More actions`,className:p(l.splitButtonTrigger,k?.triggerButton),style:A?.triggerButton})})]})}export{v as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{ButtonSize as n,ButtonStyleType as r}from"../button/button.types.mjs";import{renderIcon as i}from"../utils/renderIcon.mjs";import a from"../button/button.mjs";import o from"../interactableDiv/index.mjs";import{Align as s}from"../floatingMenu/floatingMenu.types.mjs";import c from"../floatingMenu/floatingMenu.mjs";import l from"../buttonGroup/buttonGroup.mjs";import u from"./splitButton.module.mjs";import{useEffect as d,useRef as f,useState as p}from"react";import m from"classnames";import{faChevronDown as h}from"@fortawesome/free-solid-svg-icons";import{jsx as g,jsxs as _}from"react/jsx-runtime";var v={moreActions:`More actions`};function y(e,t){return(e%t+t)%t}function b(b){let{children:x,onClick:S=()=>{},actions:C=[],styleType:w=r.Primary,size:T=n.Default,disabled:E=!1,isLoading:D=!1,align:O=s.Right,className:k,style:A,classNames:j,styles:M,labels:N,...P}=e(`SplitButton`,b),F=t(`SplitButton`,N,v),[I,L]=p(!1),R=f([]),[z,B]=p(E);E!==z&&(B(E),E&&L(!1)),d(()=>{if(!I)return;let e=C.findIndex(e=>!e.disabled);e!==-1&&R.current[e]?.focus()},[I]);function V(e,t){let n=C.map((e,t)=>t).filter(e=>!C[e].disabled);if(n.length===0)return;let r=n.indexOf(e),i=r===-1?t===1?0:n.length-1:y(r+t,n.length);R.current[n[i]]?.focus()}function H(e){let t=R.current.findIndex(e=>e===document.activeElement);e.key===`ArrowDown`?(e.preventDefault(),V(t,1)):e.key===`ArrowUp`?(e.preventDefault(),V(t,-1)):e.key===`Home`?(e.preventDefault(),V(-1,1)):e.key===`End`&&(e.preventDefault(),V(-1,-1))}return _(l,{...P,className:m(u.splitButton,j?.root,k),style:{...A,...M?.root},children:[g(a,{styleType:w,size:T,disabled:E,isLoading:D,onClick:S,className:m(u.splitButtonPrimary,j?.primaryButton),style:M?.primaryButton,children:x}),g(c,{isOpen:I,onOpenChange:L,align:O,dontCloseOnChildClick:!0,content:g(`ul`,{className:m(u.splitButtonMenu,j?.menu),style:M?.menu,role:`menu`,onKeyDown:H,children:C.map((e,t)=>g(`li`,{role:`none`,children:_(o,{ref:e=>{R.current[t]=e},role:`menuitem`,tabIndex:e.disabled?-1:0,"aria-disabled":e.disabled,className:m(u.splitButtonMenuItem,{[u.splitButtonMenuItemDisabled]:e.disabled},j?.menuItem),style:M?.menuItem,onClick:()=>{E||e.disabled||(e.onClick(),L(!1))},children:[e.icon?i(e.icon,{className:u.splitButtonMenuItemIcon}):null,e.label]})},e.id))}),children:g(a,{styleType:w,size:T,disabled:E,icon:h,"aria-label":F.moreActions,className:m(u.splitButtonTrigger,j?.triggerButton),style:M?.triggerButton})})]})}export{b as default};
2
2
  //# sourceMappingURL=splitButton.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"splitButton.mjs","names":[],"sources":["../../../../package/common/splitButton/splitButton.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { KeyboardEvent } from 'react';\nimport cx from 'classnames';\nimport { faChevronDown } from '@fortawesome/free-solid-svg-icons';\n\nimport Button from '../button';\nimport { ButtonStyleType, ButtonSize } from '../button/button.types';\nimport ButtonGroup from '../buttonGroup';\nimport FloatingMenu from '../floatingMenu';\nimport { Align } from '../floatingMenu/floatingMenu.types';\nimport InteractableDiv from '../interactableDiv';\nimport { useComponentDefaults } from '../configProvider';\nimport type { SplitButtonProps } from './splitButton.types';\n\nimport styles from './splitButton.module.pcss';\nimport { renderIcon } from '../utils/renderIcon';\n\nfunction mod(n: number, m: number) {\n return ((n % m) + m) % m;\n}\n\nfunction SplitButton(props: SplitButtonProps) {\n const {\n children,\n onClick = () => {},\n actions = [],\n styleType = ButtonStyleType.Primary,\n size = ButtonSize.Default,\n disabled = false,\n isLoading = false,\n align = Align.Right,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('SplitButton', props);\n\n const [isOpen, setIsOpen] = useState(false);\n const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n // Adjusting state during render (not in an effect) on a prop change is the documented React\n // pattern for this: closing the menu as soon as `disabled` becomes true, without an extra\n // render tick or a setState-in-effect lint violation.\n const [prevDisabled, setPrevDisabled] = useState(disabled);\n if (disabled !== prevDisabled) {\n setPrevDisabled(disabled);\n if (disabled) setIsOpen(false);\n }\n\n useEffect(() => {\n if (!isOpen) return;\n const firstEnabled = actions.findIndex((action) => !action.disabled);\n if (firstEnabled !== -1) itemRefs.current[firstEnabled]?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n function focusEnabledItem(fromIndex: number, direction: 1 | -1) {\n const enabledIndexes = actions.map((action, index) => index).filter((index) => !actions[index].disabled);\n if (enabledIndexes.length === 0) return;\n\n const currentPos = enabledIndexes.indexOf(fromIndex);\n const nextPos =\n currentPos === -1\n ? direction === 1\n ? 0\n : enabledIndexes.length - 1\n : mod(currentPos + direction, enabledIndexes.length);\n itemRefs.current[enabledIndexes[nextPos]]?.focus();\n }\n\n function handleMenuKeyDown(event: KeyboardEvent<HTMLUListElement>) {\n const activeIndex = itemRefs.current.findIndex((el) => el === document.activeElement);\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n focusEnabledItem(activeIndex, 1);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n focusEnabledItem(activeIndex, -1);\n } else if (event.key === 'Home') {\n event.preventDefault();\n focusEnabledItem(-1, 1);\n } else if (event.key === 'End') {\n event.preventDefault();\n focusEnabledItem(-1, -1);\n }\n // Escape and Tab-boundary handling live in FloatingMenu itself, since any menu content with\n // focusable elements needs the same treatment, not just this one.\n }\n\n return (\n <ButtonGroup\n {...rest}\n className={cx(styles.splitButton, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <Button\n styleType={styleType}\n size={size}\n disabled={disabled}\n isLoading={isLoading}\n onClick={onClick}\n className={cx(styles.splitButtonPrimary, classNames?.primaryButton)}\n style={slotStyles?.primaryButton}\n >\n {children}\n </Button>\n\n <FloatingMenu\n isOpen={isOpen}\n onOpenChange={setIsOpen}\n align={align}\n dontCloseOnChildClick\n content={\n <ul\n className={cx(styles.splitButtonMenu, classNames?.menu)}\n style={slotStyles?.menu}\n role='menu'\n onKeyDown={handleMenuKeyDown}\n >\n {actions.map((action, index) => (\n <li key={action.id} role='none'>\n <InteractableDiv\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n role='menuitem'\n tabIndex={action.disabled ? -1 : 0}\n aria-disabled={action.disabled}\n className={cx(\n styles.splitButtonMenuItem,\n { [styles.splitButtonMenuItemDisabled]: action.disabled },\n classNames?.menuItem,\n )}\n style={slotStyles?.menuItem}\n onClick={() => {\n if (disabled || action.disabled) return;\n action.onClick();\n setIsOpen(false);\n }}\n >\n {action.icon ? renderIcon(action.icon, { className: styles.splitButtonMenuItemIcon }) : null}\n {action.label}\n </InteractableDiv>\n </li>\n ))}\n </ul>\n }\n >\n <Button\n styleType={styleType}\n size={size}\n disabled={disabled}\n icon={faChevronDown}\n aria-label='More actions'\n className={cx(styles.splitButtonTrigger, classNames?.triggerButton)}\n style={slotStyles?.triggerButton}\n />\n </FloatingMenu>\n </ButtonGroup>\n );\n}\n\nexport default SplitButton;\n"],"mappings":"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"}
1
+ {"version":3,"file":"splitButton.mjs","names":[],"sources":["../../../../package/common/splitButton/splitButton.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { KeyboardEvent } from 'react';\nimport cx from 'classnames';\nimport { faChevronDown } from '@fortawesome/free-solid-svg-icons';\n\nimport Button from '../button';\nimport { ButtonStyleType, ButtonSize } from '../button/button.types';\nimport ButtonGroup from '../buttonGroup';\nimport FloatingMenu from '../floatingMenu';\nimport { Align } from '../floatingMenu/floatingMenu.types';\nimport type { SplitButtonLabels } from './splitButton.types';\nimport InteractableDiv from '../interactableDiv';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport type { SplitButtonProps } from './splitButton.types';\n\nimport styles from './splitButton.module.pcss';\nimport { renderIcon } from '../utils/renderIcon';\n\nconst DEFAULT_LABELS: Required<SplitButtonLabels> = {\n moreActions: 'More actions',\n};\n\nfunction mod(n: number, m: number) {\n return ((n % m) + m) % m;\n}\n\nfunction SplitButton(props: SplitButtonProps) {\n const {\n children,\n onClick = () => {},\n actions = [],\n styleType = ButtonStyleType.Primary,\n size = ButtonSize.Default,\n disabled = false,\n isLoading = false,\n align = Align.Right,\n className,\n style,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('SplitButton', props);\n const text = useLabels('SplitButton', labels, DEFAULT_LABELS);\n\n const [isOpen, setIsOpen] = useState(false);\n const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n // Adjusting state during render (not in an effect) on a prop change is the documented React\n // pattern for this: closing the menu as soon as `disabled` becomes true, without an extra\n // render tick or a setState-in-effect lint violation.\n const [prevDisabled, setPrevDisabled] = useState(disabled);\n if (disabled !== prevDisabled) {\n setPrevDisabled(disabled);\n if (disabled) setIsOpen(false);\n }\n\n useEffect(() => {\n if (!isOpen) return;\n const firstEnabled = actions.findIndex((action) => !action.disabled);\n if (firstEnabled !== -1) itemRefs.current[firstEnabled]?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n function focusEnabledItem(fromIndex: number, direction: 1 | -1) {\n const enabledIndexes = actions.map((action, index) => index).filter((index) => !actions[index].disabled);\n if (enabledIndexes.length === 0) return;\n\n const currentPos = enabledIndexes.indexOf(fromIndex);\n const nextPos =\n currentPos === -1\n ? direction === 1\n ? 0\n : enabledIndexes.length - 1\n : mod(currentPos + direction, enabledIndexes.length);\n itemRefs.current[enabledIndexes[nextPos]]?.focus();\n }\n\n function handleMenuKeyDown(event: KeyboardEvent<HTMLUListElement>) {\n const activeIndex = itemRefs.current.findIndex((el) => el === document.activeElement);\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n focusEnabledItem(activeIndex, 1);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n focusEnabledItem(activeIndex, -1);\n } else if (event.key === 'Home') {\n event.preventDefault();\n focusEnabledItem(-1, 1);\n } else if (event.key === 'End') {\n event.preventDefault();\n focusEnabledItem(-1, -1);\n }\n // Escape and Tab-boundary handling live in FloatingMenu itself, since any menu content with\n // focusable elements needs the same treatment, not just this one.\n }\n\n return (\n <ButtonGroup\n {...rest}\n className={cx(styles.splitButton, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <Button\n styleType={styleType}\n size={size}\n disabled={disabled}\n isLoading={isLoading}\n onClick={onClick}\n className={cx(styles.splitButtonPrimary, classNames?.primaryButton)}\n style={slotStyles?.primaryButton}\n >\n {children}\n </Button>\n\n <FloatingMenu\n isOpen={isOpen}\n onOpenChange={setIsOpen}\n align={align}\n dontCloseOnChildClick\n content={\n <ul\n className={cx(styles.splitButtonMenu, classNames?.menu)}\n style={slotStyles?.menu}\n role='menu'\n onKeyDown={handleMenuKeyDown}\n >\n {actions.map((action, index) => (\n <li key={action.id} role='none'>\n <InteractableDiv\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n role='menuitem'\n tabIndex={action.disabled ? -1 : 0}\n aria-disabled={action.disabled}\n className={cx(\n styles.splitButtonMenuItem,\n { [styles.splitButtonMenuItemDisabled]: action.disabled },\n classNames?.menuItem,\n )}\n style={slotStyles?.menuItem}\n onClick={() => {\n if (disabled || action.disabled) return;\n action.onClick();\n setIsOpen(false);\n }}\n >\n {action.icon ? renderIcon(action.icon, { className: styles.splitButtonMenuItemIcon }) : null}\n {action.label}\n </InteractableDiv>\n </li>\n ))}\n </ul>\n }\n >\n <Button\n styleType={styleType}\n size={size}\n disabled={disabled}\n icon={faChevronDown}\n aria-label={text.moreActions}\n className={cx(styles.splitButtonTrigger, classNames?.triggerButton)}\n style={slotStyles?.triggerButton}\n />\n </FloatingMenu>\n </ButtonGroup>\n );\n}\n\nexport default SplitButton;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{ButtonSize as t}from"../button/button.types.mjs";import n from"../button/button.mjs";import r from"../actionIcon/actionIcon.mjs";import"./timer.chime.mjs";import i from"./timer.module.mjs";import{forwardRef as a,useEffect as o,useImperativeHandle as ee,useMemo as te,useRef as s,useState as c}from"react";import l from"classnames";import{faMinus as ne,faPause as re,faPlay as ie,faPlus as ae,faXmark as oe}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var se=200,ce=1e3;function le(){return typeof window<`u`&&window.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches===!0}function f(e){let t=Math.ceil(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=String(r).padStart(2,`0`),o=String(i).padStart(2,`0`);return n>0?`${n}:${a}:${o}`:`${a}:${o}`}var p=a(function(a,p){let{durationSeconds:m,autoStart:h=!0,resetOnDurationChange:ue=!0,onTick:de,onComplete:fe,onStart:pe,onPause:me,onResume:he,onCancel:ge,onAddTime:_e,onRemoveTime:ve,showControls:g=!0,hideAddButton:ye=!1,hideRemoveButton:be=!1,hidePauseButton:xe=!1,hideCancelButton:Se=!1,adjustSeconds:_=30,maxSeconds:v,label:y,formatTime:Ce=f,size:b,strokeWidth:x=10,counterClockwise:we=!1,urgentThreshold:Te=.1,urgentMinSeconds:Ee=3,pulseOnUrgent:De=!0,showRunningRipples:S=!1,playSoundOnComplete:Oe=!1,soundUrl:ke,soundVolume:C=.5,notifyOnComplete:w=!1,notificationTitle:Ae,notificationBody:je,className:Me,style:Ne,classNames:T,styles:E,...Pe}=e(`Timer`,a),D=m*1e3,[O,Fe]=c(h?`running`:`idle`),[k,Ie]=c(D),[Le,Re]=c(0),[A,j]=c([]),M=s(k),N=s(O),P=s(D),F=s(!1),I=s(!1),L=s(!1),R=s(0);function z(e){M.current=e,Ie(e)}function B(e){N.current=e,Fe(e)}function V(){Re(e=>e+1)}o(()=>{if(O!==`running`)return;let e=Date.now(),t=M.current,n=setInterval(()=>{let n=Math.max(0,t-(Date.now()-e));z(n),de?.(n),n<=0&&B(`completed`)},se);return()=>clearInterval(n)},[O,Le]),o(()=>{if(O===`completed`&&!F.current){if(F.current=!0,fe?.(),Oe)try{let e=new Audio(ke||`data:audio/wav;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANACUAKwAKAMr/kv+R/9n/TwCxALwAVwCs/xb/8/5p/0YAFgFfAeYA3f/N/lP+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`);e.volume=C,e.play()?.catch(()=>{})}catch{}if(w&&typeof Notification<`u`&&Notification.permission===`granted`)try{new Notification(Ae??`Timer done`,{body:je??(typeof y==`string`?y:void 0)})}catch{}}O!==`completed`&&(F.current=!1)},[O]),o(()=>{if(!L.current){L.current=!0;return}let e=m*1e3;P.current=e,z(e),F.current=!1,V(),ue&&B(h?`running`:`idle`)},[m]),o(()=>{if(!S||O!==`running`||le())return;function e(){R.current+=1,j(e=>[...e,R.current])}e();let t=setInterval(e,ce);return()=>clearInterval(t)},[S,O]);function ze(e){j(t=>t.filter(t=>t!==e))}function Be(){w&&!I.current&&typeof Notification<`u`&&Notification.permission==="default"&&(I.current=!0,Notification.requestPermission().catch(()=>{}))}function H(){Be(),(N.current===`completed`||N.current===`cancelled`)&&(z(P.current),F.current=!1),V(),B(`running`),pe?.()}function U(){N.current===`running`&&(B(`paused`),me?.())}function W(){N.current===`paused`&&(V(),B(`running`),he?.())}function G(e){let t=v==null?1/0:v*1e3,n=Math.min(M.current+e*1e3,t);z(n),V(),_e?.(e,Math.round(n/1e3)),N.current===`completed`&&n>0&&(F.current=!1,B(`running`))}function K(e){let t=Math.max(0,M.current-e*1e3);z(t),V(),ve?.(e,Math.round(t/1e3)),t<=0&&N.current===`running`&&B(`completed`)}function q(){z(P.current),B(`cancelled`),ge?.()}function Ve(){z(P.current),F.current=!1,B(`idle`)}ee(p,()=>({start:H,pause:U,resume:W,addTime:G,removeTime:K,cancel:q,reset:Ve,getStatus:()=>N.current,getRemainingMs:()=>M.current}));let J=50-x/2,Y=te(()=>2*Math.PI*J,[J]),He=Y*(1-(P.current>0?Math.min(1,k/P.current):0)),X=Math.max(P.current*Te,Ee*1e3),Z=O===`running`&&k<=X,Ue=Z&&k<=Math.min(5e3,X),Q=O===`paused`,We=g&&!ye,$=g&&!be,Ge=g&&!xe,Ke=O===`running`?re:ie,qe=O===`running`?`Pause`:Q?`Resume`:O===`idle`?`Start`:`Restart`,Je=O===`running`?U:Q?W:H,Ye=g&&!Se;return d(`div`,{...Pe,className:l(i.timer,De&&Z&&i.timerPulsing,Ue&&i.timerCritical,Me,T?.root),style:{...b?{"--timer-size":b}:null,"--timer-stroke-width":`${x}px`,...Ne,...E?.root},children:[d(`div`,{className:l(i.timerRingWrapper,T?.ringWrapper),style:E?.ringWrapper,children:[A.length>0&&u(`div`,{className:l(i.timerRipples,T?.ripples),style:E?.ripples,children:A.map(e=>u(`span`,{className:l(i.timerRipple,T?.ripple),style:E?.ripple,onAnimationEnd:()=>ze(e)},e))}),d(`svg`,{className:l(i.timerRingSvg,T?.ringSvg),viewBox:`0 0 100 100`,style:E?.ringSvg,children:[u(`circle`,{className:l(i.timerRingTrack,T?.ringTrack),cx:`50`,cy:`50`,r:J,style:E?.ringTrack}),u(`circle`,{className:l(i.timerRingProgress,Z&&i.timerRingProgressUrgent,T?.ringProgress),cx:`50`,cy:`50`,r:J,strokeDasharray:Y,strokeDashoffset:He,style:{transition:Q?`none`:void 0,transform:we?`rotate(-90deg)`:void 0,...E?.ringProgress}})]}),d(`div`,{className:l(i.timerDisplay,T?.display),style:E?.display,children:[u(`span`,{className:l(i.timerTime,T?.time),style:E?.time,children:Ce(k)}),y&&u(`span`,{className:l(i.timerLabel,T?.label),style:E?.label,children:y})]})]}),g&&d(`div`,{className:l(i.timerControls,T?.controls),style:E?.controls,children:[d(`div`,{className:i.timerControlsRow,children:[$&&u(r,{icon:ne,title:`Remove ${_}s`,onClick:()=>K(_),className:l(i.timerAdjustButton,T?.removeButton),style:E?.removeButton}),Ge&&u(n,{size:t.Small,icon:Ke,title:qe,onClick:Je,className:T?.pauseButton,style:E?.pauseButton}),We&&u(r,{icon:ae,title:`Add ${_}s`,onClick:()=>G(_),className:l(i.timerAdjustButton,T?.addButton),style:E?.addButton})]}),Ye&&u(r,{icon:oe,title:`Cancel timer`,onClick:q,className:l(i.timerCancelButton,T?.cancelButton),style:E?.cancelButton})]})]})});p.displayName=`Timer`;export{p as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{ButtonSize as n}from"../button/button.types.mjs";import r from"../button/button.mjs";import i from"../actionIcon/actionIcon.mjs";import"./timer.chime.mjs";import a from"./timer.module.mjs";import{forwardRef as o,useEffect as s,useImperativeHandle as ee,useMemo as te,useRef as c,useState as l}from"react";import u from"classnames";import{faMinus as ne,faPause as re,faPlay as ie,faPlus as ae,faXmark as oe}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var se=200,ce=1e3,le={cancel:`Cancel timer`};function ue(){return typeof window<`u`&&window.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches===!0}function de(e){let t=Math.ceil(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=String(r).padStart(2,`0`),o=String(i).padStart(2,`0`);return n>0?`${n}:${a}:${o}`:`${a}:${o}`}var p=o(function(o,p){let{durationSeconds:m,autoStart:h=!0,resetOnDurationChange:fe=!0,onTick:pe,onComplete:me,onStart:he,onPause:ge,onResume:_e,onCancel:ve,onAddTime:ye,onRemoveTime:be,showControls:g=!0,hideAddButton:xe=!1,hideRemoveButton:Se=!1,hidePauseButton:Ce=!1,hideCancelButton:we=!1,adjustSeconds:_=30,maxSeconds:v,label:y,formatTime:Te=de,size:b,strokeWidth:x=10,counterClockwise:Ee=!1,urgentThreshold:De=.1,urgentMinSeconds:Oe=3,pulseOnUrgent:ke=!0,showRunningRipples:S=!1,playSoundOnComplete:Ae=!1,soundUrl:C,soundVolume:je=.5,notifyOnComplete:w=!1,notificationTitle:Me,notificationBody:Ne,className:Pe,style:Fe,classNames:T,styles:E,labels:Ie,...Le}=e(`Timer`,o),Re=t(`Timer`,Ie,le),D=m*1e3,[O,ze]=l(h?`running`:`idle`),[k,Be]=l(D),[Ve,A]=l(0),[j,M]=l([]),N=c(k),P=c(O),F=c(D),I=c(!1),L=c(!1),R=c(!1),z=c(0);function B(e){N.current=e,Be(e)}function V(e){P.current=e,ze(e)}function H(){A(e=>e+1)}s(()=>{if(O!==`running`)return;let e=Date.now(),t=N.current,n=setInterval(()=>{let n=Math.max(0,t-(Date.now()-e));B(n),pe?.(n),n<=0&&V(`completed`)},se);return()=>clearInterval(n)},[O,Ve]),s(()=>{if(O===`completed`&&!I.current){if(I.current=!0,me?.(),Ae)try{let e=new Audio(C||`data:audio/wav;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANACUAKwAKAMr/kv+R/9n/TwCxALwAVwCs/xb/8/5p/0YAFgFfAeYA3f/N/lP+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`);e.volume=je,e.play()?.catch(()=>{})}catch{}if(w&&typeof Notification<`u`&&Notification.permission===`granted`)try{new Notification(Me??`Timer done`,{body:Ne??(typeof y==`string`?y:void 0)})}catch{}}O!==`completed`&&(I.current=!1)},[O]),s(()=>{if(!R.current){R.current=!0;return}let e=m*1e3;F.current=e,B(e),I.current=!1,H(),fe&&V(h?`running`:`idle`)},[m]),s(()=>{if(!S||O!==`running`||ue())return;function e(){z.current+=1,M(e=>[...e,z.current])}e();let t=setInterval(e,ce);return()=>clearInterval(t)},[S,O]);function He(e){M(t=>t.filter(t=>t!==e))}function Ue(){w&&!L.current&&typeof Notification<`u`&&Notification.permission==="default"&&(L.current=!0,Notification.requestPermission().catch(()=>{}))}function U(){Ue(),(P.current===`completed`||P.current===`cancelled`)&&(B(F.current),I.current=!1),H(),V(`running`),he?.()}function W(){P.current===`running`&&(V(`paused`),ge?.())}function G(){P.current===`paused`&&(H(),V(`running`),_e?.())}function K(e){let t=v==null?1/0:v*1e3,n=Math.min(N.current+e*1e3,t);B(n),H(),ye?.(e,Math.round(n/1e3)),P.current===`completed`&&n>0&&(I.current=!1,V(`running`))}function q(e){let t=Math.max(0,N.current-e*1e3);B(t),H(),be?.(e,Math.round(t/1e3)),t<=0&&P.current===`running`&&V(`completed`)}function J(){B(F.current),V(`cancelled`),ve?.()}function We(){B(F.current),I.current=!1,V(`idle`)}ee(p,()=>({start:U,pause:W,resume:G,addTime:K,removeTime:q,cancel:J,reset:We,getStatus:()=>P.current,getRemainingMs:()=>N.current}));let Y=50-x/2,X=te(()=>2*Math.PI*Y,[Y]),Ge=X*(1-(F.current>0?Math.min(1,k/F.current):0)),Z=Math.max(F.current*De,Oe*1e3),Q=O===`running`&&k<=Z,Ke=Q&&k<=Math.min(5e3,Z),$=O===`paused`,qe=g&&!xe,Je=g&&!Se,Ye=g&&!Ce,Xe=O===`running`?re:ie,Ze=O===`running`?`Pause`:$?`Resume`:O===`idle`?`Start`:`Restart`,Qe=O===`running`?W:$?G:U,$e=g&&!we;return f(`div`,{...Le,className:u(a.timer,ke&&Q&&a.timerPulsing,Ke&&a.timerCritical,Pe,T?.root),style:{...b?{"--timer-size":b}:null,"--timer-stroke-width":`${x}px`,...Fe,...E?.root},children:[f(`div`,{className:u(a.timerRingWrapper,T?.ringWrapper),style:E?.ringWrapper,children:[j.length>0&&d(`div`,{className:u(a.timerRipples,T?.ripples),style:E?.ripples,children:j.map(e=>d(`span`,{className:u(a.timerRipple,T?.ripple),style:E?.ripple,onAnimationEnd:()=>He(e)},e))}),f(`svg`,{className:u(a.timerRingSvg,T?.ringSvg),viewBox:`0 0 100 100`,style:E?.ringSvg,children:[d(`circle`,{className:u(a.timerRingTrack,T?.ringTrack),cx:`50`,cy:`50`,r:Y,style:E?.ringTrack}),d(`circle`,{className:u(a.timerRingProgress,Q&&a.timerRingProgressUrgent,T?.ringProgress),cx:`50`,cy:`50`,r:Y,strokeDasharray:X,strokeDashoffset:Ge,style:{transition:$?`none`:void 0,transform:Ee?`rotate(-90deg)`:void 0,...E?.ringProgress}})]}),f(`div`,{className:u(a.timerDisplay,T?.display),style:E?.display,children:[d(`span`,{className:u(a.timerTime,T?.time),style:E?.time,children:Te(k)}),y&&d(`span`,{className:u(a.timerLabel,T?.label),style:E?.label,children:y})]})]}),g&&f(`div`,{className:u(a.timerControls,T?.controls),style:E?.controls,children:[f(`div`,{className:a.timerControlsRow,children:[Je&&d(i,{icon:ne,title:`Remove ${_}s`,onClick:()=>q(_),className:u(a.timerAdjustButton,T?.removeButton),style:E?.removeButton}),Ye&&d(r,{size:n.Small,icon:Xe,title:Ze,onClick:Qe,className:T?.pauseButton,style:E?.pauseButton}),qe&&d(i,{icon:ae,title:`Add ${_}s`,onClick:()=>K(_),className:u(a.timerAdjustButton,T?.addButton),style:E?.addButton})]}),$e&&d(i,{icon:oe,title:Re.cancel,onClick:J,className:u(a.timerCancelButton,T?.cancelButton),style:E?.cancelButton})]})]})});p.displayName=`Timer`;export{p as default};
2
2
  //# sourceMappingURL=timer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"timer.mjs","names":[],"sources":["../../../../package/common/timer/timer.tsx"],"sourcesContent":["import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { faPlus, faMinus, faPause, faPlay, faXmark } from '@fortawesome/free-solid-svg-icons';\n\nimport ActionIcon from '../actionIcon';\nimport Button from '../button';\nimport { ButtonSize } from '../button/button.types';\nimport { useComponentDefaults } from '../configProvider';\nimport { DEFAULT_CHIME_DATA_URI } from './timer.chime';\nimport type { TimerHandle, TimerProps, TimerStatus } from './timer.types';\nimport styles from './timer.module.pcss';\n\nconst TICK_MS = 200;\nconst RIPPLE_SPAWN_INTERVAL_MS = 1000;\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n}\n\nfunction formatTimeDefault(remainingMs: number) {\n const totalSeconds = Math.ceil(remainingMs / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const mm = String(minutes).padStart(2, '0');\n const ss = String(seconds).padStart(2, '0');\n return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;\n}\n\nconst Timer = forwardRef<TimerHandle, TimerProps>(function Timer(props, ref) {\n const {\n durationSeconds,\n autoStart = true,\n resetOnDurationChange = true,\n\n onTick,\n onComplete,\n onStart,\n onPause,\n onResume,\n onCancel,\n onAddTime,\n onRemoveTime,\n\n showControls = true,\n hideAddButton = false,\n hideRemoveButton = false,\n hidePauseButton = false,\n hideCancelButton = false,\n adjustSeconds = 30,\n maxSeconds,\n\n label,\n formatTime = formatTimeDefault,\n size,\n strokeWidth = 10,\n counterClockwise = false,\n\n urgentThreshold = 0.1,\n urgentMinSeconds = 3,\n pulseOnUrgent = true,\n showRunningRipples = false,\n\n playSoundOnComplete = false,\n soundUrl,\n soundVolume = 0.5,\n notifyOnComplete = false,\n notificationTitle,\n notificationBody,\n\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Timer', props);\n\n const initialMs = durationSeconds * 1000;\n const [status, setStatusState] = useState<TimerStatus>(autoStart ? 'running' : 'idle');\n const [remainingMs, setRemainingMsState] = useState(initialMs);\n const [epoch, setEpoch] = useState(0);\n const [ripples, setRipples] = useState<number[]>([]);\n\n const remainingRef = useRef(remainingMs);\n const statusRef = useRef(status);\n const totalMsRef = useRef(initialMs);\n const completedFiredRef = useRef(false);\n const notifyPermissionRequestedRef = useRef(false);\n const mountedRef = useRef(false);\n const rippleIdRef = useRef(0);\n\n function setRemaining(next: number) {\n remainingRef.current = next;\n setRemainingMsState(next);\n }\n\n function setStatus(next: TimerStatus) {\n statusRef.current = next;\n setStatusState(next);\n }\n\n function bumpEpoch() {\n setEpoch((e) => e + 1);\n }\n\n // Ticking effect. Re-derives the remaining time from Date.now() every tick (rather than\n // accumulating setInterval's own drift), so it stays accurate over long countdowns. Any\n // external mutation of remainingRef (addTime/removeTime while already running, or a resume)\n // must bump `epoch` so this effect re-arms and re-captures a fresh start/startRemaining —\n // without that, a stale `startRemaining` captured before the mutation would silently\n // overwrite it on the next tick.\n useEffect(() => {\n if (status !== 'running') return undefined;\n const start = Date.now();\n const startRemaining = remainingRef.current;\n const id = setInterval(() => {\n const next = Math.max(0, startRemaining - (Date.now() - start));\n setRemaining(next);\n onTick?.(next);\n if (next <= 0) setStatus('completed');\n }, TICK_MS);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status, epoch]);\n\n // Fires onComplete exactly once per completion, plus the opt-in sound/notification.\n useEffect(() => {\n if (status === 'completed' && !completedFiredRef.current) {\n completedFiredRef.current = true;\n onComplete?.();\n if (playSoundOnComplete) {\n try {\n const audio = new Audio(soundUrl || DEFAULT_CHIME_DATA_URI);\n audio.volume = soundVolume;\n // play() can reject (autoplay policy) or, in some environments, return undefined\n // instead of a Promise — never let a blocked/unsupported playback surface as an error.\n audio.play()?.catch(() => {});\n } catch {\n // Audio unavailable/unsupported — fail silently.\n }\n }\n if (notifyOnComplete && typeof Notification !== 'undefined' && Notification.permission === 'granted') {\n try {\n new Notification(notificationTitle ?? 'Timer done', {\n body: notificationBody ?? (typeof label === 'string' ? label : undefined),\n });\n } catch {\n // Some browsers (e.g. certain mobile Safari versions) throw constructing\n // Notification outside specific contexts — fail silently, as documented.\n }\n }\n }\n if (status !== 'completed') completedFiredRef.current = false;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status]);\n\n // durationSeconds prop change: reset (and optionally restart) at the new duration. Skips\n // the initial mount, since autoStart/initial state already cover that.\n useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n const nextMs = durationSeconds * 1000;\n totalMsRef.current = nextMs;\n setRemaining(nextMs);\n completedFiredRef.current = false;\n bumpEpoch();\n if (resetOnDurationChange) {\n setStatus(autoStart ? 'running' : 'idle');\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [durationSeconds]);\n\n // Running-ripple spawner: spawns a new ripple roughly every RIPPLE_SPAWN_INTERVAL_MS while\n // running, each animating once (via CSS, `forwards`) and removing itself on `onAnimationEnd`.\n // Pausing (or otherwise leaving `running`) only stops new spawns here — it doesn't touch\n // `ripples` — so whichever ripples are already mid-flight keep animating to completion\n // instead of vanishing mid-cycle.\n useEffect(() => {\n if (!showRunningRipples || status !== 'running' || prefersReducedMotion()) return undefined;\n function spawnRipple() {\n rippleIdRef.current += 1;\n setRipples((prev) => [...prev, rippleIdRef.current]);\n }\n spawnRipple();\n const id = setInterval(spawnRipple, RIPPLE_SPAWN_INTERVAL_MS);\n return () => clearInterval(id);\n }, [showRunningRipples, status]);\n\n function handleRippleAnimationEnd(id: number) {\n setRipples((prev) => prev.filter((existingId) => existingId !== id));\n }\n\n function requestNotificationPermissionIfNeeded() {\n if (!notifyOnComplete || notifyPermissionRequestedRef.current) return;\n if (typeof Notification === 'undefined' || Notification.permission !== 'default') return;\n notifyPermissionRequestedRef.current = true;\n Notification.requestPermission().catch(() => {});\n }\n\n function start() {\n requestNotificationPermissionIfNeeded();\n if (statusRef.current === 'completed' || statusRef.current === 'cancelled') {\n setRemaining(totalMsRef.current);\n completedFiredRef.current = false;\n }\n bumpEpoch();\n setStatus('running');\n onStart?.();\n }\n\n function pause() {\n if (statusRef.current !== 'running') return;\n setStatus('paused');\n onPause?.();\n }\n\n function resume() {\n if (statusRef.current !== 'paused') return;\n bumpEpoch();\n setStatus('running');\n onResume?.();\n }\n\n function addTime(seconds: number) {\n const capped = maxSeconds != null ? maxSeconds * 1000 : Infinity;\n const next = Math.min(remainingRef.current + seconds * 1000, capped);\n setRemaining(next);\n bumpEpoch();\n onAddTime?.(seconds, Math.round(next / 1000));\n if (statusRef.current === 'completed' && next > 0) {\n completedFiredRef.current = false;\n setStatus('running');\n }\n }\n\n function removeTime(seconds: number) {\n const next = Math.max(0, remainingRef.current - seconds * 1000);\n setRemaining(next);\n bumpEpoch();\n onRemoveTime?.(seconds, Math.round(next / 1000));\n if (next <= 0 && statusRef.current === 'running') setStatus('completed');\n }\n\n function cancel() {\n setRemaining(totalMsRef.current);\n setStatus('cancelled');\n onCancel?.();\n }\n\n function reset() {\n setRemaining(totalMsRef.current);\n completedFiredRef.current = false;\n setStatus('idle');\n }\n\n useImperativeHandle(ref, () => ({\n start,\n pause,\n resume,\n addTime,\n removeTime,\n cancel,\n reset,\n getStatus: () => statusRef.current,\n getRemainingMs: () => remainingRef.current,\n }));\n\n const radius = 50 - strokeWidth / 2;\n const circumference = useMemo(() => 2 * Math.PI * radius, [radius]);\n const clampedFraction = totalMsRef.current > 0 ? Math.min(1, remainingMs / totalMsRef.current) : 0;\n const dashOffset = circumference * (1 - clampedFraction);\n const urgentMs = Math.max(totalMsRef.current * urgentThreshold, urgentMinSeconds * 1000);\n const isUrgent = status === 'running' && remainingMs <= urgentMs;\n const isCritical = isUrgent && remainingMs <= Math.min(5000, urgentMs);\n const isPaused = status === 'paused';\n\n // The pause button doubles as a play/restart button whenever there's nothing to pause —\n // idle (autoStart={false}), completed, or cancelled — rather than hiding itself, so there's\n // always a way to (re)start the countdown from the built-in controls alone.\n const showAddButton = showControls && !hideAddButton;\n const showRemoveButton = showControls && !hideRemoveButton;\n const showPauseButton = showControls && !hidePauseButton;\n const pauseButtonIcon = status === 'running' ? faPause : faPlay;\n const pauseButtonTitle =\n status === 'running' ? 'Pause' : isPaused ? 'Resume' : status === 'idle' ? 'Start' : 'Restart';\n const handlePauseButtonClick = status === 'running' ? pause : isPaused ? resume : start;\n const showCancelButton = showControls && !hideCancelButton;\n\n return (\n <div\n {...rest}\n className={cx(\n styles.timer,\n pulseOnUrgent && isUrgent && styles.timerPulsing,\n isCritical && styles.timerCritical,\n className,\n classNames?.root,\n )}\n style={\n {\n ...(size ? { '--timer-size': size } : null),\n '--timer-stroke-width': `${strokeWidth}px`,\n ...style,\n ...slotStyles?.root,\n } as React.CSSProperties\n }\n >\n <div className={cx(styles.timerRingWrapper, classNames?.ringWrapper)} style={slotStyles?.ringWrapper}>\n {ripples.length > 0 && (\n <div className={cx(styles.timerRipples, classNames?.ripples)} style={slotStyles?.ripples}>\n {ripples.map((id) => (\n <span\n key={id}\n className={cx(styles.timerRipple, classNames?.ripple)}\n style={slotStyles?.ripple}\n onAnimationEnd={() => handleRippleAnimationEnd(id)}\n />\n ))}\n </div>\n )}\n <svg className={cx(styles.timerRingSvg, classNames?.ringSvg)} viewBox='0 0 100 100' style={slotStyles?.ringSvg}>\n <circle\n className={cx(styles.timerRingTrack, classNames?.ringTrack)}\n cx='50'\n cy='50'\n r={radius}\n style={slotStyles?.ringTrack}\n />\n <circle\n className={cx(\n styles.timerRingProgress,\n isUrgent && styles.timerRingProgressUrgent,\n classNames?.ringProgress,\n )}\n cx='50'\n cy='50'\n r={radius}\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n style={{\n transition: isPaused ? 'none' : undefined,\n transform: counterClockwise ? 'rotate(-90deg)' : undefined,\n ...slotStyles?.ringProgress,\n }}\n />\n </svg>\n <div className={cx(styles.timerDisplay, classNames?.display)} style={slotStyles?.display}>\n <span className={cx(styles.timerTime, classNames?.time)} style={slotStyles?.time}>\n {formatTime(remainingMs)}\n </span>\n {label && (\n <span className={cx(styles.timerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n </span>\n )}\n </div>\n </div>\n\n {showControls && (\n <div className={cx(styles.timerControls, classNames?.controls)} style={slotStyles?.controls}>\n <div className={styles.timerControlsRow}>\n {showRemoveButton && (\n <ActionIcon\n icon={faMinus}\n title={`Remove ${adjustSeconds}s`}\n onClick={() => removeTime(adjustSeconds)}\n className={cx(styles.timerAdjustButton, classNames?.removeButton)}\n style={slotStyles?.removeButton}\n />\n )}\n {showPauseButton && (\n <Button\n size={ButtonSize.Small}\n icon={pauseButtonIcon}\n title={pauseButtonTitle}\n onClick={handlePauseButtonClick}\n className={classNames?.pauseButton}\n style={slotStyles?.pauseButton}\n />\n )}\n {showAddButton && (\n <ActionIcon\n icon={faPlus}\n title={`Add ${adjustSeconds}s`}\n onClick={() => addTime(adjustSeconds)}\n className={cx(styles.timerAdjustButton, classNames?.addButton)}\n style={slotStyles?.addButton}\n />\n )}\n </div>\n {showCancelButton && (\n <ActionIcon\n icon={faXmark}\n title='Cancel timer'\n onClick={cancel}\n className={cx(styles.timerCancelButton, classNames?.cancelButton)}\n style={slotStyles?.cancelButton}\n />\n )}\n </div>\n )}\n </div>\n );\n});\n\nTimer.displayName = 'Timer';\n\nexport default Timer;\n"],"mappings":"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"}
1
+ {"version":3,"file":"timer.mjs","names":[],"sources":["../../../../package/common/timer/timer.tsx"],"sourcesContent":["import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { faPlus, faMinus, faPause, faPlay, faXmark } from '@fortawesome/free-solid-svg-icons';\n\nimport ActionIcon from '../actionIcon';\nimport Button from '../button';\nimport { ButtonSize } from '../button/button.types';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { DEFAULT_CHIME_DATA_URI } from './timer.chime';\nimport type { TimerHandle, TimerLabels, TimerProps, TimerStatus } from './timer.types';\nimport styles from './timer.module.pcss';\n\nconst TICK_MS = 200;\nconst RIPPLE_SPAWN_INTERVAL_MS = 1000;\n\nconst DEFAULT_LABELS: Required<TimerLabels> = {\n cancel: 'Cancel timer',\n};\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n}\n\nfunction formatTimeDefault(remainingMs: number) {\n const totalSeconds = Math.ceil(remainingMs / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const mm = String(minutes).padStart(2, '0');\n const ss = String(seconds).padStart(2, '0');\n return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;\n}\n\nconst Timer = forwardRef<TimerHandle, TimerProps>(function Timer(props, ref) {\n const {\n durationSeconds,\n autoStart = true,\n resetOnDurationChange = true,\n\n onTick,\n onComplete,\n onStart,\n onPause,\n onResume,\n onCancel,\n onAddTime,\n onRemoveTime,\n\n showControls = true,\n hideAddButton = false,\n hideRemoveButton = false,\n hidePauseButton = false,\n hideCancelButton = false,\n adjustSeconds = 30,\n maxSeconds,\n\n label,\n formatTime = formatTimeDefault,\n size,\n strokeWidth = 10,\n counterClockwise = false,\n\n urgentThreshold = 0.1,\n urgentMinSeconds = 3,\n pulseOnUrgent = true,\n showRunningRipples = false,\n\n playSoundOnComplete = false,\n soundUrl,\n soundVolume = 0.5,\n notifyOnComplete = false,\n notificationTitle,\n notificationBody,\n\n className,\n style,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('Timer', props);\n const text = useLabels('Timer', labels, DEFAULT_LABELS);\n\n const initialMs = durationSeconds * 1000;\n const [status, setStatusState] = useState<TimerStatus>(autoStart ? 'running' : 'idle');\n const [remainingMs, setRemainingMsState] = useState(initialMs);\n const [epoch, setEpoch] = useState(0);\n const [ripples, setRipples] = useState<number[]>([]);\n\n const remainingRef = useRef(remainingMs);\n const statusRef = useRef(status);\n const totalMsRef = useRef(initialMs);\n const completedFiredRef = useRef(false);\n const notifyPermissionRequestedRef = useRef(false);\n const mountedRef = useRef(false);\n const rippleIdRef = useRef(0);\n\n function setRemaining(next: number) {\n remainingRef.current = next;\n setRemainingMsState(next);\n }\n\n function setStatus(next: TimerStatus) {\n statusRef.current = next;\n setStatusState(next);\n }\n\n function bumpEpoch() {\n setEpoch((e) => e + 1);\n }\n\n // Ticking effect. Re-derives the remaining time from Date.now() every tick (rather than\n // accumulating setInterval's own drift), so it stays accurate over long countdowns. Any\n // external mutation of remainingRef (addTime/removeTime while already running, or a resume)\n // must bump `epoch` so this effect re-arms and re-captures a fresh start/startRemaining —\n // without that, a stale `startRemaining` captured before the mutation would silently\n // overwrite it on the next tick.\n useEffect(() => {\n if (status !== 'running') return undefined;\n const start = Date.now();\n const startRemaining = remainingRef.current;\n const id = setInterval(() => {\n const next = Math.max(0, startRemaining - (Date.now() - start));\n setRemaining(next);\n onTick?.(next);\n if (next <= 0) setStatus('completed');\n }, TICK_MS);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status, epoch]);\n\n // Fires onComplete exactly once per completion, plus the opt-in sound/notification.\n useEffect(() => {\n if (status === 'completed' && !completedFiredRef.current) {\n completedFiredRef.current = true;\n onComplete?.();\n if (playSoundOnComplete) {\n try {\n const audio = new Audio(soundUrl || DEFAULT_CHIME_DATA_URI);\n audio.volume = soundVolume;\n // play() can reject (autoplay policy) or, in some environments, return undefined\n // instead of a Promise — never let a blocked/unsupported playback surface as an error.\n audio.play()?.catch(() => {});\n } catch {\n // Audio unavailable/unsupported — fail silently.\n }\n }\n if (notifyOnComplete && typeof Notification !== 'undefined' && Notification.permission === 'granted') {\n try {\n new Notification(notificationTitle ?? 'Timer done', {\n body: notificationBody ?? (typeof label === 'string' ? label : undefined),\n });\n } catch {\n // Some browsers (e.g. certain mobile Safari versions) throw constructing\n // Notification outside specific contexts — fail silently, as documented.\n }\n }\n }\n if (status !== 'completed') completedFiredRef.current = false;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [status]);\n\n // durationSeconds prop change: reset (and optionally restart) at the new duration. Skips\n // the initial mount, since autoStart/initial state already cover that.\n useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n const nextMs = durationSeconds * 1000;\n totalMsRef.current = nextMs;\n setRemaining(nextMs);\n completedFiredRef.current = false;\n bumpEpoch();\n if (resetOnDurationChange) {\n setStatus(autoStart ? 'running' : 'idle');\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [durationSeconds]);\n\n // Running-ripple spawner: spawns a new ripple roughly every RIPPLE_SPAWN_INTERVAL_MS while\n // running, each animating once (via CSS, `forwards`) and removing itself on `onAnimationEnd`.\n // Pausing (or otherwise leaving `running`) only stops new spawns here — it doesn't touch\n // `ripples` — so whichever ripples are already mid-flight keep animating to completion\n // instead of vanishing mid-cycle.\n useEffect(() => {\n if (!showRunningRipples || status !== 'running' || prefersReducedMotion()) return undefined;\n function spawnRipple() {\n rippleIdRef.current += 1;\n setRipples((prev) => [...prev, rippleIdRef.current]);\n }\n spawnRipple();\n const id = setInterval(spawnRipple, RIPPLE_SPAWN_INTERVAL_MS);\n return () => clearInterval(id);\n }, [showRunningRipples, status]);\n\n function handleRippleAnimationEnd(id: number) {\n setRipples((prev) => prev.filter((existingId) => existingId !== id));\n }\n\n function requestNotificationPermissionIfNeeded() {\n if (!notifyOnComplete || notifyPermissionRequestedRef.current) return;\n if (typeof Notification === 'undefined' || Notification.permission !== 'default') return;\n notifyPermissionRequestedRef.current = true;\n Notification.requestPermission().catch(() => {});\n }\n\n function start() {\n requestNotificationPermissionIfNeeded();\n if (statusRef.current === 'completed' || statusRef.current === 'cancelled') {\n setRemaining(totalMsRef.current);\n completedFiredRef.current = false;\n }\n bumpEpoch();\n setStatus('running');\n onStart?.();\n }\n\n function pause() {\n if (statusRef.current !== 'running') return;\n setStatus('paused');\n onPause?.();\n }\n\n function resume() {\n if (statusRef.current !== 'paused') return;\n bumpEpoch();\n setStatus('running');\n onResume?.();\n }\n\n function addTime(seconds: number) {\n const capped = maxSeconds != null ? maxSeconds * 1000 : Infinity;\n const next = Math.min(remainingRef.current + seconds * 1000, capped);\n setRemaining(next);\n bumpEpoch();\n onAddTime?.(seconds, Math.round(next / 1000));\n if (statusRef.current === 'completed' && next > 0) {\n completedFiredRef.current = false;\n setStatus('running');\n }\n }\n\n function removeTime(seconds: number) {\n const next = Math.max(0, remainingRef.current - seconds * 1000);\n setRemaining(next);\n bumpEpoch();\n onRemoveTime?.(seconds, Math.round(next / 1000));\n if (next <= 0 && statusRef.current === 'running') setStatus('completed');\n }\n\n function cancel() {\n setRemaining(totalMsRef.current);\n setStatus('cancelled');\n onCancel?.();\n }\n\n function reset() {\n setRemaining(totalMsRef.current);\n completedFiredRef.current = false;\n setStatus('idle');\n }\n\n useImperativeHandle(ref, () => ({\n start,\n pause,\n resume,\n addTime,\n removeTime,\n cancel,\n reset,\n getStatus: () => statusRef.current,\n getRemainingMs: () => remainingRef.current,\n }));\n\n const radius = 50 - strokeWidth / 2;\n const circumference = useMemo(() => 2 * Math.PI * radius, [radius]);\n const clampedFraction = totalMsRef.current > 0 ? Math.min(1, remainingMs / totalMsRef.current) : 0;\n const dashOffset = circumference * (1 - clampedFraction);\n const urgentMs = Math.max(totalMsRef.current * urgentThreshold, urgentMinSeconds * 1000);\n const isUrgent = status === 'running' && remainingMs <= urgentMs;\n const isCritical = isUrgent && remainingMs <= Math.min(5000, urgentMs);\n const isPaused = status === 'paused';\n\n // The pause button doubles as a play/restart button whenever there's nothing to pause —\n // idle (autoStart={false}), completed, or cancelled — rather than hiding itself, so there's\n // always a way to (re)start the countdown from the built-in controls alone.\n const showAddButton = showControls && !hideAddButton;\n const showRemoveButton = showControls && !hideRemoveButton;\n const showPauseButton = showControls && !hidePauseButton;\n const pauseButtonIcon = status === 'running' ? faPause : faPlay;\n const pauseButtonTitle =\n status === 'running' ? 'Pause' : isPaused ? 'Resume' : status === 'idle' ? 'Start' : 'Restart';\n const handlePauseButtonClick = status === 'running' ? pause : isPaused ? resume : start;\n const showCancelButton = showControls && !hideCancelButton;\n\n return (\n <div\n {...rest}\n className={cx(\n styles.timer,\n pulseOnUrgent && isUrgent && styles.timerPulsing,\n isCritical && styles.timerCritical,\n className,\n classNames?.root,\n )}\n style={\n {\n ...(size ? { '--timer-size': size } : null),\n '--timer-stroke-width': `${strokeWidth}px`,\n ...style,\n ...slotStyles?.root,\n } as React.CSSProperties\n }\n >\n <div className={cx(styles.timerRingWrapper, classNames?.ringWrapper)} style={slotStyles?.ringWrapper}>\n {ripples.length > 0 && (\n <div className={cx(styles.timerRipples, classNames?.ripples)} style={slotStyles?.ripples}>\n {ripples.map((id) => (\n <span\n key={id}\n className={cx(styles.timerRipple, classNames?.ripple)}\n style={slotStyles?.ripple}\n onAnimationEnd={() => handleRippleAnimationEnd(id)}\n />\n ))}\n </div>\n )}\n <svg className={cx(styles.timerRingSvg, classNames?.ringSvg)} viewBox='0 0 100 100' style={slotStyles?.ringSvg}>\n <circle\n className={cx(styles.timerRingTrack, classNames?.ringTrack)}\n cx='50'\n cy='50'\n r={radius}\n style={slotStyles?.ringTrack}\n />\n <circle\n className={cx(\n styles.timerRingProgress,\n isUrgent && styles.timerRingProgressUrgent,\n classNames?.ringProgress,\n )}\n cx='50'\n cy='50'\n r={radius}\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n style={{\n transition: isPaused ? 'none' : undefined,\n transform: counterClockwise ? 'rotate(-90deg)' : undefined,\n ...slotStyles?.ringProgress,\n }}\n />\n </svg>\n <div className={cx(styles.timerDisplay, classNames?.display)} style={slotStyles?.display}>\n <span className={cx(styles.timerTime, classNames?.time)} style={slotStyles?.time}>\n {formatTime(remainingMs)}\n </span>\n {label && (\n <span className={cx(styles.timerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n </span>\n )}\n </div>\n </div>\n\n {showControls && (\n <div className={cx(styles.timerControls, classNames?.controls)} style={slotStyles?.controls}>\n <div className={styles.timerControlsRow}>\n {showRemoveButton && (\n <ActionIcon\n icon={faMinus}\n title={`Remove ${adjustSeconds}s`}\n onClick={() => removeTime(adjustSeconds)}\n className={cx(styles.timerAdjustButton, classNames?.removeButton)}\n style={slotStyles?.removeButton}\n />\n )}\n {showPauseButton && (\n <Button\n size={ButtonSize.Small}\n icon={pauseButtonIcon}\n title={pauseButtonTitle}\n onClick={handlePauseButtonClick}\n className={classNames?.pauseButton}\n style={slotStyles?.pauseButton}\n />\n )}\n {showAddButton && (\n <ActionIcon\n icon={faPlus}\n title={`Add ${adjustSeconds}s`}\n onClick={() => addTime(adjustSeconds)}\n className={cx(styles.timerAdjustButton, classNames?.addButton)}\n style={slotStyles?.addButton}\n />\n )}\n </div>\n {showCancelButton && (\n <ActionIcon\n icon={faXmark}\n title={text.cancel}\n onClick={cancel}\n className={cx(styles.timerCancelButton, classNames?.cancelButton)}\n style={slotStyles?.cancelButton}\n />\n )}\n </div>\n )}\n </div>\n );\n});\n\nTimer.displayName = 'Timer';\n\nexport default Timer;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"../actionIcon/actionIcon.mjs";import t from"./toast.module.mjs";import{useSwipeDismiss as n}from"../hooks/useSwipeDismiss.mjs";import{useEffect as r,useRef as i,useState as a}from"react";import o from"classnames";import{FontAwesomeIcon as s}from"@fortawesome/react-fontawesome";import{faBell as c,faCircleCheck as l,faCircleInfo as u,faCircleXmark as d,faTriangleExclamation as f,faXmark as p}from"@fortawesome/free-solid-svg-icons";import{jsx as m,jsxs as h}from"react/jsx-runtime";var g={info:u,success:l,error:d,warn:f,default:c};function _({item:c,isBottom:l,onDismiss:u}){let{id:d,content:f,options:_,dismissing:v}=c,{duration:y,showRemainingTime:b,showCloseButton:x,pauseOnHover:S,type:C,classNames:w,styles:T}=_,[E,D]=a(!1),[O,k]=a(!1),[A,j]=a(!1),{ref:M,isDragging:N}=n({onDismiss:()=>{j(!0),u(d)}}),P=S&&(E||O)||N,F=i(y);return r(()=>{if(y===0||P)return;let e=Date.now(),t=setTimeout(()=>u(d),F.current);return()=>{clearTimeout(t),F.current-=Date.now()-e}},[d,y,u,P]),h(`div`,{ref:M,className:o(t.toast,l?t.toastBottom:null,t[`toast-${C}`],v&&!A&&t.toastDismissing,P&&t.toastPaused,w?.root),style:T?.root,onMouseEnter:S?()=>D(!0):void 0,onMouseLeave:S?()=>D(!1):void 0,onFocus:S?()=>k(!0):void 0,onBlur:S?()=>k(!1):void 0,children:[m(s,{icon:g[C],className:o(t.toastIcon,w?.icon),style:T?.icon}),m(`div`,{className:o(t.toastContent,w?.content),style:T?.content,children:f}),x&&m(e,{icon:p,onClick:()=>u(d),className:o(t.toastCloseButton,w?.closeButton),style:T?.closeButton,"aria-label":`Close`}),b&&y>0&&m(`div`,{className:o(t.toastProgressBar,w?.progressBar),style:{"--toast-duration":`${y}ms`,...T?.progressBar}})]})}export{_ as default};
1
+ import e from"../actionIcon/actionIcon.mjs";import t from"./toast.module.mjs";import{useSwipeDismiss as n}from"../hooks/useSwipeDismiss.mjs";import{useEffect as r,useRef as i,useState as a}from"react";import o from"classnames";import{FontAwesomeIcon as s}from"@fortawesome/react-fontawesome";import{faBell as c,faCircleCheck as l,faCircleInfo as u,faCircleXmark as d,faTriangleExclamation as f,faXmark as p}from"@fortawesome/free-solid-svg-icons";import{jsx as m,jsxs as h}from"react/jsx-runtime";var g={info:u,success:l,error:d,warn:f,default:c};function _({item:c,isBottom:l,onDismiss:u,labels:d}){let{id:f,content:_,options:v,dismissing:y}=c,{duration:b,showRemainingTime:x,showCloseButton:S,pauseOnHover:C,type:w,classNames:T,styles:E}=v,[D,O]=a(!1),[k,A]=a(!1),[j,M]=a(!1),{ref:N,isDragging:P}=n({onDismiss:()=>{M(!0),u(f)}}),F=C&&(D||k)||P,I=i(b);return r(()=>{if(b===0||F)return;let e=Date.now(),t=setTimeout(()=>u(f),I.current);return()=>{clearTimeout(t),I.current-=Date.now()-e}},[f,b,u,F]),h(`div`,{ref:N,className:o(t.toast,l?t.toastBottom:null,t[`toast-${w}`],y&&!j&&t.toastDismissing,F&&t.toastPaused,T?.root),style:E?.root,onMouseEnter:C?()=>O(!0):void 0,onMouseLeave:C?()=>O(!1):void 0,onFocus:C?()=>A(!0):void 0,onBlur:C?()=>A(!1):void 0,children:[m(s,{icon:g[w],className:o(t.toastIcon,T?.icon),style:E?.icon}),m(`div`,{className:o(t.toastContent,T?.content),style:E?.content,children:_}),S&&m(e,{icon:p,onClick:()=>u(f),className:o(t.toastCloseButton,T?.closeButton),style:E?.closeButton,"aria-label":d.close}),x&&b>0&&m(`div`,{className:o(t.toastProgressBar,T?.progressBar),style:{"--toast-duration":`${b}ms`,...E?.progressBar}})]})}export{_ as default};
2
2
  //# sourceMappingURL=toast.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.mjs","names":[],"sources":["../../../../package/common/toast/toast.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faCircleInfo,\n faCircleCheck,\n faCircleXmark,\n faTriangleExclamation,\n faBell,\n faXmark,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './toast.module.pcss';\nimport type { ToastItem } from './toast.types';\nimport ActionIcon from '../actionIcon';\nimport { useSwipeDismiss } from '../hooks/useSwipeDismiss';\n\ninterface ToastProps {\n item: ToastItem;\n isBottom: boolean;\n onDismiss: (id: string) => void;\n}\n\nconst typeIcons = {\n info: faCircleInfo,\n success: faCircleCheck,\n error: faCircleXmark,\n warn: faTriangleExclamation,\n default: faBell,\n};\n\nfunction Toast({ item, isBottom, onDismiss }: ToastProps) {\n const { id, content, options, dismissing } = item;\n const { duration, showRemainingTime, showCloseButton, pauseOnHover, type, classNames, styles: slotStyles } = options;\n\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n\n const [swiped, setSwiped] = useState(false);\n const { ref: swipeRef, isDragging } = useSwipeDismiss<HTMLDivElement>({\n onDismiss: () => {\n setSwiped(true);\n onDismiss(id);\n },\n });\n\n const paused = (pauseOnHover && (hovered || focused)) || isDragging;\n\n // Remaining time is carried across pause/resume cycles so the timer continues\n // where it left off instead of restarting on every hover.\n const remainingRef = useRef(duration);\n\n useEffect(() => {\n if (duration === 0 || paused) return;\n const start = Date.now();\n const timer = setTimeout(() => onDismiss(id), remainingRef.current);\n return () => {\n clearTimeout(timer);\n remainingRef.current -= Date.now() - start;\n };\n }, [id, duration, onDismiss, paused]);\n\n return (\n <div\n ref={swipeRef}\n className={cx(\n styles.toast,\n isBottom ? styles.toastBottom : null,\n styles[`toast-${type}`],\n dismissing && !swiped && styles.toastDismissing,\n paused && styles.toastPaused,\n classNames?.root,\n )}\n style={slotStyles?.root}\n onMouseEnter={pauseOnHover ? () => setHovered(true) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(false) : undefined}\n onFocus={pauseOnHover ? () => setFocused(true) : undefined}\n onBlur={pauseOnHover ? () => setFocused(false) : undefined}\n >\n <FontAwesomeIcon\n icon={typeIcons[type]}\n className={cx(styles.toastIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n\n <div className={cx(styles.toastContent, classNames?.content)} style={slotStyles?.content}>\n {content}\n </div>\n\n {showCloseButton && (\n <ActionIcon\n icon={faXmark}\n onClick={() => onDismiss(id)}\n className={cx(styles.toastCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n aria-label='Close'\n />\n )}\n\n {showRemainingTime && duration > 0 && (\n <div\n className={cx(styles.toastProgressBar, classNames?.progressBar)}\n style={{ '--toast-duration': `${duration}ms`, ...slotStyles?.progressBar } as React.CSSProperties}\n />\n )}\n </div>\n );\n}\n\nexport default Toast;\n"],"mappings":"ifAuBA,IAAM,EAAY,CAChB,KAAM,EACN,QAAS,EACT,MAAO,EACP,KAAM,EACN,QAAS,CACX,EAEA,SAAS,EAAM,CAAE,OAAM,WAAU,aAAyB,CACxD,GAAM,CAAE,KAAI,UAAS,UAAS,cAAe,EACvC,CAAE,WAAU,oBAAmB,kBAAiB,eAAc,OAAM,aAAY,OAAQ,GAAe,EAEvG,CAAC,EAAS,GAAc,EAAS,EAAK,EACtC,CAAC,EAAS,GAAc,EAAS,EAAK,EAEtC,CAAC,EAAQ,GAAa,EAAS,EAAK,EACpC,CAAE,IAAK,EAAU,cAAe,EAAgC,CACpE,cAAiB,CACf,EAAU,EAAI,EACd,EAAU,CAAE,CACd,CACF,CAAC,EAEK,EAAU,IAAiB,GAAW,IAAa,EAInD,EAAe,EAAO,CAAQ,EAYpC,OAVA,MAAgB,CACd,GAAI,IAAa,GAAK,EAAQ,OAC9B,IAAM,EAAQ,KAAK,IAAI,EACjB,EAAQ,eAAiB,EAAU,CAAE,EAAG,EAAa,OAAO,EAClE,UAAa,CACX,aAAa,CAAK,EAClB,EAAa,SAAW,KAAK,IAAI,EAAI,CACvC,CACF,EAAG,CAAC,EAAI,EAAU,EAAW,CAAM,CAAC,EAGlC,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EACT,EAAO,MACP,EAAW,EAAO,YAAc,KAChC,EAAO,SAAS,KAChB,GAAc,CAAC,GAAU,EAAO,gBAChC,GAAU,EAAO,YACjB,GAAY,IACd,EACA,MAAO,GAAY,KACnB,aAAc,MAAqB,EAAW,EAAI,EAAI,IAAA,GACtD,aAAc,MAAqB,EAAW,EAAK,EAAI,IAAA,GACvD,QAAS,MAAqB,EAAW,EAAI,EAAI,IAAA,GACjD,OAAQ,MAAqB,EAAW,EAAK,EAAI,IAAA,GAdnD,SAAA,CAgBE,EAAC,EAAD,CACE,KAAM,EAAU,GAChB,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAChD,MAAO,GAAY,IACpB,CAAA,EAED,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,aAAc,GAAY,OAAO,EAAG,MAAO,GAAY,QAC9E,SAAA,CACE,CAAA,EAEJ,GACC,EAAC,EAAD,CACE,KAAM,EACN,YAAe,EAAU,CAAE,EAC3B,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YACnB,aAAW,OACZ,CAAA,EAGF,GAAqB,EAAW,GAC/B,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,CAAE,mBAAoB,GAAG,EAAS,IAAK,GAAG,GAAY,WAAY,CAC1E,CAAA,CAEA,GAET"}
1
+ {"version":3,"file":"toast.mjs","names":[],"sources":["../../../../package/common/toast/toast.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faCircleInfo,\n faCircleCheck,\n faCircleXmark,\n faTriangleExclamation,\n faBell,\n faXmark,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './toast.module.pcss';\nimport type { ToastItem, ToastLabels } from './toast.types';\nimport ActionIcon from '../actionIcon';\nimport { useSwipeDismiss } from '../hooks/useSwipeDismiss';\n\ninterface ToastProps {\n item: ToastItem;\n isBottom: boolean;\n onDismiss: (id: string) => void;\n /** Already resolved by the provider: defaults, provider, then this toast's own. */\n labels: Required<ToastLabels>;\n}\n\nconst typeIcons = {\n info: faCircleInfo,\n success: faCircleCheck,\n error: faCircleXmark,\n warn: faTriangleExclamation,\n default: faBell,\n};\n\nfunction Toast({ item, isBottom, onDismiss, labels }: ToastProps) {\n const { id, content, options, dismissing } = item;\n const { duration, showRemainingTime, showCloseButton, pauseOnHover, type, classNames, styles: slotStyles } = options;\n\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n\n const [swiped, setSwiped] = useState(false);\n const { ref: swipeRef, isDragging } = useSwipeDismiss<HTMLDivElement>({\n onDismiss: () => {\n setSwiped(true);\n onDismiss(id);\n },\n });\n\n const paused = (pauseOnHover && (hovered || focused)) || isDragging;\n\n // Remaining time is carried across pause/resume cycles so the timer continues\n // where it left off instead of restarting on every hover.\n const remainingRef = useRef(duration);\n\n useEffect(() => {\n if (duration === 0 || paused) return;\n const start = Date.now();\n const timer = setTimeout(() => onDismiss(id), remainingRef.current);\n return () => {\n clearTimeout(timer);\n remainingRef.current -= Date.now() - start;\n };\n }, [id, duration, onDismiss, paused]);\n\n return (\n <div\n ref={swipeRef}\n className={cx(\n styles.toast,\n isBottom ? styles.toastBottom : null,\n styles[`toast-${type}`],\n dismissing && !swiped && styles.toastDismissing,\n paused && styles.toastPaused,\n classNames?.root,\n )}\n style={slotStyles?.root}\n onMouseEnter={pauseOnHover ? () => setHovered(true) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(false) : undefined}\n onFocus={pauseOnHover ? () => setFocused(true) : undefined}\n onBlur={pauseOnHover ? () => setFocused(false) : undefined}\n >\n <FontAwesomeIcon\n icon={typeIcons[type]}\n className={cx(styles.toastIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n\n <div className={cx(styles.toastContent, classNames?.content)} style={slotStyles?.content}>\n {content}\n </div>\n\n {showCloseButton && (\n <ActionIcon\n icon={faXmark}\n onClick={() => onDismiss(id)}\n className={cx(styles.toastCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n aria-label={labels.close}\n />\n )}\n\n {showRemainingTime && duration > 0 && (\n <div\n className={cx(styles.toastProgressBar, classNames?.progressBar)}\n style={{ '--toast-duration': `${duration}ms`, ...slotStyles?.progressBar } as React.CSSProperties}\n />\n )}\n </div>\n );\n}\n\nexport default Toast;\n"],"mappings":"ifAyBA,IAAM,EAAY,CAChB,KAAM,EACN,QAAS,EACT,MAAO,EACP,KAAM,EACN,QAAS,CACX,EAEA,SAAS,EAAM,CAAE,OAAM,WAAU,YAAW,UAAsB,CAChE,GAAM,CAAE,KAAI,UAAS,UAAS,cAAe,EACvC,CAAE,WAAU,oBAAmB,kBAAiB,eAAc,OAAM,aAAY,OAAQ,GAAe,EAEvG,CAAC,EAAS,GAAc,EAAS,EAAK,EACtC,CAAC,EAAS,GAAc,EAAS,EAAK,EAEtC,CAAC,EAAQ,GAAa,EAAS,EAAK,EACpC,CAAE,IAAK,EAAU,cAAe,EAAgC,CACpE,cAAiB,CACf,EAAU,EAAI,EACd,EAAU,CAAE,CACd,CACF,CAAC,EAEK,EAAU,IAAiB,GAAW,IAAa,EAInD,EAAe,EAAO,CAAQ,EAYpC,OAVA,MAAgB,CACd,GAAI,IAAa,GAAK,EAAQ,OAC9B,IAAM,EAAQ,KAAK,IAAI,EACjB,EAAQ,eAAiB,EAAU,CAAE,EAAG,EAAa,OAAO,EAClE,UAAa,CACX,aAAa,CAAK,EAClB,EAAa,SAAW,KAAK,IAAI,EAAI,CACvC,CACF,EAAG,CAAC,EAAI,EAAU,EAAW,CAAM,CAAC,EAGlC,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EACT,EAAO,MACP,EAAW,EAAO,YAAc,KAChC,EAAO,SAAS,KAChB,GAAc,CAAC,GAAU,EAAO,gBAChC,GAAU,EAAO,YACjB,GAAY,IACd,EACA,MAAO,GAAY,KACnB,aAAc,MAAqB,EAAW,EAAI,EAAI,IAAA,GACtD,aAAc,MAAqB,EAAW,EAAK,EAAI,IAAA,GACvD,QAAS,MAAqB,EAAW,EAAI,EAAI,IAAA,GACjD,OAAQ,MAAqB,EAAW,EAAK,EAAI,IAAA,GAdnD,SAAA,CAgBE,EAAC,EAAD,CACE,KAAM,EAAU,GAChB,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAChD,MAAO,GAAY,IACpB,CAAA,EAED,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,aAAc,GAAY,OAAO,EAAG,MAAO,GAAY,QAC9E,SAAA,CACE,CAAA,EAEJ,GACC,EAAC,EAAD,CACE,KAAM,EACN,YAAe,EAAU,CAAE,EAC3B,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YACnB,aAAY,EAAO,KACpB,CAAA,EAGF,GAAqB,EAAW,GAC/B,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,CAAE,mBAAoB,GAAG,EAAS,IAAK,GAAG,GAAY,WAAY,CAC1E,CAAA,CAEA,GAET"}
@@ -1,2 +1,2 @@
1
- import e from"../bodyEnd/bodyEnd.mjs";import t from"./toast.module.mjs";import n from"./toast.mjs";import{_registerToastHandler as r,_unregisterToastHandler as i}from"./toastService.mjs";import{useCallback as a,useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{Fragment as u,jsx as d,jsxs as f}from"react/jsx-runtime";var p={position:`top-right`,duration:4e3,showRemainingTime:!0,showCloseButton:!0,allowStacking:!0,pauseOnHover:!0},m=220;function h(e){return t[`container-${e}`]}function g({children:g,position:_=p.position,duration:v=p.duration,showRemainingTime:y=p.showRemainingTime,showCloseButton:b=p.showCloseButton,allowStacking:x=p.allowStacking,pauseOnHover:S=p.pauseOnHover}){let[C,w]=c([]),T=s(0),E=a(e=>{w(t=>t.map(t=>t.id===e?{...t,dismissing:!0}:t)),setTimeout(()=>{w(t=>t.filter(t=>t.id!==e))},m)},[]),D=a((e,t)=>{let n={position:t?.position??_,duration:t?.duration??v,showRemainingTime:t?.showRemainingTime??y,showCloseButton:t?.showCloseButton??b,pauseOnHover:t?.pauseOnHover??S,type:t?.type??`default`,classNames:t?.classNames,styles:t?.styles};T.current+=1;let r={id:`toast-${T.current}`,content:e,options:n,dismissing:!1};w(e=>!x&&e.length>0?(setTimeout(()=>{w([r])},m),e.map(e=>({...e,dismissing:!0}))):[...e,r])},[_,v,y,b,x,S]);o(()=>(r(D),()=>i()),[D]);let O=C.reduce((e,t)=>{let n=t.options.position;return e[n]||(e[n]=[]),e[n].push(t),e},{});return f(u,{children:[g,d(e,{children:Object.entries(O).map(([e,r])=>d(`div`,{className:l(t.container,h(e)),children:r.map(t=>d(n,{item:t,isBottom:e.startsWith(`bottom`),onDismiss:E},t.id))},e))})]})}export{g as default};
1
+ import e from"../bodyEnd/bodyEnd.mjs";import t from"./toast.module.mjs";import n from"./toast.mjs";import{_registerToastHandler as r,_unregisterToastHandler as i}from"./toastService.mjs";import{useCallback as a,useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{Fragment as u,jsx as d,jsxs as f}from"react/jsx-runtime";var p={position:`top-right`,duration:4e3,showRemainingTime:!0,showCloseButton:!0,allowStacking:!0,pauseOnHover:!0,labels:{close:`Close`}},m=220;function h(e){return t[`container-${e}`]}function g({children:g,position:_=p.position,duration:v=p.duration,showRemainingTime:y=p.showRemainingTime,showCloseButton:b=p.showCloseButton,allowStacking:x=p.allowStacking,pauseOnHover:S=p.pauseOnHover,labels:C}){let[w,T]=c([]),E=s(0),D=a(e=>{T(t=>t.map(t=>t.id===e?{...t,dismissing:!0}:t)),setTimeout(()=>{T(t=>t.filter(t=>t.id!==e))},m)},[]),O=a((e,t)=>{let n={position:t?.position??_,duration:t?.duration??v,showRemainingTime:t?.showRemainingTime??y,showCloseButton:t?.showCloseButton??b,pauseOnHover:t?.pauseOnHover??S,type:t?.type??`default`,classNames:t?.classNames,styles:t?.styles};E.current+=1;let r={id:`toast-${E.current}`,content:e,options:n,dismissing:!1};T(e=>!x&&e.length>0?(setTimeout(()=>{T([r])},m),e.map(e=>({...e,dismissing:!0}))):[...e,r])},[_,v,y,b,x,S]);o(()=>(r(O),()=>i()),[O]);let k=w.reduce((e,t)=>{let n=t.options.position;return e[n]||(e[n]=[]),e[n].push(t),e},{});return f(u,{children:[g,d(e,{children:Object.entries(k).map(([e,r])=>d(`div`,{className:l(t.container,h(e)),children:r.map(t=>d(n,{item:t,isBottom:e.startsWith(`bottom`),onDismiss:D,labels:{...p.labels,...C,...t.labels}},t.id))},e))})]})}export{g as default};
2
2
  //# sourceMappingURL=toastProvider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"toastProvider.mjs","names":[],"sources":["../../../../package/common/toast/toastProvider.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './toast.module.pcss';\nimport Toast from './toast';\nimport { _registerToastHandler, _unregisterToastHandler } from './toastService';\nimport type { ToastContextConfig, ToastItem, ToastOptions, ResolvedToastOptions, ToastPosition } from './toast.types';\nimport type { ReactNode } from 'react';\n\nconst DEFAULTS: Required<ToastContextConfig> = {\n position: 'top-right',\n duration: 4000,\n showRemainingTime: true,\n showCloseButton: true,\n allowStacking: true,\n pauseOnHover: true,\n};\n\nconst DISMISS_ANIMATION_MS = 220;\n\nfunction positionToClass(position: ToastPosition): string {\n return styles[`container-${position}`];\n}\n\ninterface ToastProviderProps extends ToastContextConfig {\n children: ReactNode;\n}\n\nfunction ToastProvider({\n children,\n position = DEFAULTS.position,\n duration = DEFAULTS.duration,\n showRemainingTime = DEFAULTS.showRemainingTime,\n showCloseButton = DEFAULTS.showCloseButton,\n allowStacking = DEFAULTS.allowStacking,\n pauseOnHover = DEFAULTS.pauseOnHover,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const counterRef = useRef(0);\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.map((t) => (t.id === id ? { ...t, dismissing: true } : t)));\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, DISMISS_ANIMATION_MS);\n }, []);\n\n const addToast = useCallback(\n (content: ReactNode, options?: ToastOptions) => {\n const resolved: ResolvedToastOptions = {\n position: options?.position ?? position,\n duration: options?.duration ?? duration,\n showRemainingTime: options?.showRemainingTime ?? showRemainingTime,\n showCloseButton: options?.showCloseButton ?? showCloseButton,\n pauseOnHover: options?.pauseOnHover ?? pauseOnHover,\n type: options?.type ?? 'default',\n classNames: options?.classNames,\n styles: options?.styles,\n };\n\n counterRef.current += 1;\n const id = `toast-${counterRef.current}`;\n const newToast: ToastItem = { id, content, options: resolved, dismissing: false };\n\n setToasts((prev) => {\n if (!allowStacking && prev.length > 0) {\n // Mark all existing as dismissing, then replace\n setTimeout(() => {\n setToasts([newToast]);\n }, DISMISS_ANIMATION_MS);\n return prev.map((t) => ({ ...t, dismissing: true }));\n }\n return [...prev, newToast];\n });\n },\n [position, duration, showRemainingTime, showCloseButton, allowStacking, pauseOnHover],\n );\n\n useEffect(() => {\n _registerToastHandler(addToast);\n return () => _unregisterToastHandler();\n }, [addToast]);\n\n // Group toasts by position so per-toast position overrides work correctly\n const byPosition = toasts.reduce<Record<string, ToastItem[]>>((acc, t) => {\n const pos = t.options.position;\n if (!acc[pos]) acc[pos] = [];\n acc[pos].push(t);\n return acc;\n }, {});\n\n return (\n <>\n {children}\n <BodyEnd>\n {Object.entries(byPosition).map(([pos, items]) => (\n <div key={pos} className={cx(styles.container, positionToClass(pos as typeof position))}>\n {items.map((item) => (\n <Toast key={item.id} item={item} isBottom={pos.startsWith('bottom')} onDismiss={dismiss} />\n ))}\n </div>\n ))}\n </BodyEnd>\n </>\n );\n}\n\nexport default ToastProvider;\nexport type { ToastProviderProps };\n"],"mappings":"kWAUA,IAAM,EAAyC,CAC7C,SAAU,YACV,SAAU,IACV,kBAAmB,GACnB,gBAAiB,GACjB,cAAe,GACf,aAAc,EAChB,EAEM,EAAuB,IAE7B,SAAS,EAAgB,EAAiC,CACxD,OAAO,EAAO,aAAa,IAC7B,CAMA,SAAS,EAAc,CACrB,WACA,WAAW,EAAS,SACpB,WAAW,EAAS,SACpB,oBAAoB,EAAS,kBAC7B,kBAAkB,EAAS,gBAC3B,gBAAgB,EAAS,cACzB,eAAe,EAAS,cACH,CACrB,GAAM,CAAC,EAAQ,GAAa,EAAsB,CAAC,CAAC,EAC9C,EAAa,EAAO,CAAC,EAErB,EAAU,EAAa,GAAe,CAC1C,EAAW,GAAS,EAAK,IAAK,GAAO,EAAE,KAAO,EAAK,CAAE,GAAG,EAAG,WAAY,EAAK,EAAI,CAAE,CAAC,EACnF,eAAiB,CACf,EAAW,GAAS,EAAK,OAAQ,GAAM,EAAE,KAAO,CAAE,CAAC,CACrD,EAAG,CAAoB,CACzB,EAAG,CAAC,CAAC,EAEC,EAAW,GACd,EAAoB,IAA2B,CAC9C,IAAM,EAAiC,CACrC,SAAU,GAAS,UAAY,EAC/B,SAAU,GAAS,UAAY,EAC/B,kBAAmB,GAAS,mBAAqB,EACjD,gBAAiB,GAAS,iBAAmB,EAC7C,aAAc,GAAS,cAAgB,EACvC,KAAM,GAAS,MAAQ,UACvB,WAAY,GAAS,WACrB,OAAQ,GAAS,MACnB,EAEA,EAAW,SAAW,EAEtB,IAAM,EAAsB,CAAE,GAAA,SADV,EAAW,UACG,UAAS,QAAS,EAAU,WAAY,EAAM,EAEhF,EAAW,GACL,CAAC,GAAiB,EAAK,OAAS,GAElC,eAAiB,CACf,EAAU,CAAC,CAAQ,CAAC,CACtB,EAAG,CAAoB,EAChB,EAAK,IAAK,IAAO,CAAE,GAAG,EAAG,WAAY,EAAK,EAAE,GAE9C,CAAC,GAAG,EAAM,CAAQ,CAC1B,CACH,EACA,CAAC,EAAU,EAAU,EAAmB,EAAiB,EAAe,CAAY,CACtF,EAEA,OACE,EAAsB,CAAQ,MACjB,EAAwB,GACpC,CAAC,CAAQ,CAAC,EAGb,IAAM,EAAa,EAAO,QAAqC,EAAK,IAAM,CACxE,IAAM,EAAM,EAAE,QAAQ,SAGtB,OAFK,EAAI,KAAM,EAAI,GAAO,CAAC,GAC3B,EAAI,EAAI,CAAC,KAAK,CAAC,EACR,CACT,EAAG,CAAC,CAAC,EAEL,OACE,EAAA,EAAA,CAAA,SAAA,CACG,EACD,EAAC,EAAD,CAAA,SACG,OAAO,QAAQ,CAAU,CAAC,CAAC,KAAK,CAAC,EAAK,KACrC,EAAC,MAAD,CAAe,UAAW,EAAG,EAAO,UAAW,EAAgB,CAAsB,CAAC,EACnF,SAAA,EAAM,IAAK,GACV,EAAC,EAAD,CAA2B,OAAM,SAAU,EAAI,WAAW,QAAQ,EAAG,UAAW,CAAU,EAA9E,EAAK,EAAyE,CAC3F,CACE,EAJK,CAIL,CACN,CACM,CAAA,CACT,CAAA,CAAA,CAEN"}
1
+ {"version":3,"file":"toastProvider.mjs","names":[],"sources":["../../../../package/common/toast/toastProvider.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './toast.module.pcss';\nimport Toast from './toast';\nimport { _registerToastHandler, _unregisterToastHandler } from './toastService';\nimport type {\n ToastContextConfig,\n ToastItem,\n ToastOptions,\n ResolvedToastOptions,\n ToastPosition,\n ToastLabels,\n} from './toast.types';\nimport type { ReactNode } from 'react';\n\nconst DEFAULTS: Required<ToastContextConfig> = {\n position: 'top-right',\n duration: 4000,\n showRemainingTime: true,\n showCloseButton: true,\n allowStacking: true,\n pauseOnHover: true,\n labels: { close: 'Close' },\n};\n\nconst DISMISS_ANIMATION_MS = 220;\n\nfunction positionToClass(position: ToastPosition): string {\n return styles[`container-${position}`];\n}\n\ninterface ToastProviderProps extends ToastContextConfig {\n children: ReactNode;\n}\n\nfunction ToastProvider({\n children,\n position = DEFAULTS.position,\n duration = DEFAULTS.duration,\n showRemainingTime = DEFAULTS.showRemainingTime,\n showCloseButton = DEFAULTS.showCloseButton,\n allowStacking = DEFAULTS.allowStacking,\n pauseOnHover = DEFAULTS.pauseOnHover,\n labels,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const counterRef = useRef(0);\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.map((t) => (t.id === id ? { ...t, dismissing: true } : t)));\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, DISMISS_ANIMATION_MS);\n }, []);\n\n const addToast = useCallback(\n (content: ReactNode, options?: ToastOptions) => {\n const resolved: ResolvedToastOptions = {\n position: options?.position ?? position,\n duration: options?.duration ?? duration,\n showRemainingTime: options?.showRemainingTime ?? showRemainingTime,\n showCloseButton: options?.showCloseButton ?? showCloseButton,\n pauseOnHover: options?.pauseOnHover ?? pauseOnHover,\n type: options?.type ?? 'default',\n classNames: options?.classNames,\n styles: options?.styles,\n };\n\n counterRef.current += 1;\n const id = `toast-${counterRef.current}`;\n const newToast: ToastItem = { id, content, options: resolved, dismissing: false };\n\n setToasts((prev) => {\n if (!allowStacking && prev.length > 0) {\n // Mark all existing as dismissing, then replace\n setTimeout(() => {\n setToasts([newToast]);\n }, DISMISS_ANIMATION_MS);\n return prev.map((t) => ({ ...t, dismissing: true }));\n }\n return [...prev, newToast];\n });\n },\n [position, duration, showRemainingTime, showCloseButton, allowStacking, pauseOnHover],\n );\n\n useEffect(() => {\n _registerToastHandler(addToast);\n return () => _unregisterToastHandler();\n }, [addToast]);\n\n // Group toasts by position so per-toast position overrides work correctly\n const byPosition = toasts.reduce<Record<string, ToastItem[]>>((acc, t) => {\n const pos = t.options.position;\n if (!acc[pos]) acc[pos] = [];\n acc[pos].push(t);\n return acc;\n }, {});\n\n return (\n <>\n {children}\n <BodyEnd>\n {Object.entries(byPosition).map(([pos, items]) => (\n <div key={pos} className={cx(styles.container, positionToClass(pos as typeof position))}>\n {items.map((item) => (\n <Toast\n key={item.id}\n item={item}\n isBottom={pos.startsWith('bottom')}\n onDismiss={dismiss}\n labels={{ ...DEFAULTS.labels, ...labels, ...item.labels } as Required<ToastLabels>}\n />\n ))}\n </div>\n ))}\n </BodyEnd>\n </>\n );\n}\n\nexport default ToastProvider;\nexport type { ToastProviderProps };\n"],"mappings":"kWAiBA,IAAM,EAAyC,CAC7C,SAAU,YACV,SAAU,IACV,kBAAmB,GACnB,gBAAiB,GACjB,cAAe,GACf,aAAc,GACd,OAAQ,CAAE,MAAO,OAAQ,CAC3B,EAEM,EAAuB,IAE7B,SAAS,EAAgB,EAAiC,CACxD,OAAO,EAAO,aAAa,IAC7B,CAMA,SAAS,EAAc,CACrB,WACA,WAAW,EAAS,SACpB,WAAW,EAAS,SACpB,oBAAoB,EAAS,kBAC7B,kBAAkB,EAAS,gBAC3B,gBAAgB,EAAS,cACzB,eAAe,EAAS,aACxB,UACqB,CACrB,GAAM,CAAC,EAAQ,GAAa,EAAsB,CAAC,CAAC,EAC9C,EAAa,EAAO,CAAC,EAErB,EAAU,EAAa,GAAe,CAC1C,EAAW,GAAS,EAAK,IAAK,GAAO,EAAE,KAAO,EAAK,CAAE,GAAG,EAAG,WAAY,EAAK,EAAI,CAAE,CAAC,EACnF,eAAiB,CACf,EAAW,GAAS,EAAK,OAAQ,GAAM,EAAE,KAAO,CAAE,CAAC,CACrD,EAAG,CAAoB,CACzB,EAAG,CAAC,CAAC,EAEC,EAAW,GACd,EAAoB,IAA2B,CAC9C,IAAM,EAAiC,CACrC,SAAU,GAAS,UAAY,EAC/B,SAAU,GAAS,UAAY,EAC/B,kBAAmB,GAAS,mBAAqB,EACjD,gBAAiB,GAAS,iBAAmB,EAC7C,aAAc,GAAS,cAAgB,EACvC,KAAM,GAAS,MAAQ,UACvB,WAAY,GAAS,WACrB,OAAQ,GAAS,MACnB,EAEA,EAAW,SAAW,EAEtB,IAAM,EAAsB,CAAE,GAAA,SADV,EAAW,UACG,UAAS,QAAS,EAAU,WAAY,EAAM,EAEhF,EAAW,GACL,CAAC,GAAiB,EAAK,OAAS,GAElC,eAAiB,CACf,EAAU,CAAC,CAAQ,CAAC,CACtB,EAAG,CAAoB,EAChB,EAAK,IAAK,IAAO,CAAE,GAAG,EAAG,WAAY,EAAK,EAAE,GAE9C,CAAC,GAAG,EAAM,CAAQ,CAC1B,CACH,EACA,CAAC,EAAU,EAAU,EAAmB,EAAiB,EAAe,CAAY,CACtF,EAEA,OACE,EAAsB,CAAQ,MACjB,EAAwB,GACpC,CAAC,CAAQ,CAAC,EAGb,IAAM,EAAa,EAAO,QAAqC,EAAK,IAAM,CACxE,IAAM,EAAM,EAAE,QAAQ,SAGtB,OAFK,EAAI,KAAM,EAAI,GAAO,CAAC,GAC3B,EAAI,EAAI,CAAC,KAAK,CAAC,EACR,CACT,EAAG,CAAC,CAAC,EAEL,OACE,EAAA,EAAA,CAAA,SAAA,CACG,EACD,EAAC,EAAD,CAAA,SACG,OAAO,QAAQ,CAAU,CAAC,CAAC,KAAK,CAAC,EAAK,KACrC,EAAC,MAAD,CAAe,UAAW,EAAG,EAAO,UAAW,EAAgB,CAAsB,CAAC,EACnF,SAAA,EAAM,IAAK,GACV,EAAC,EAAD,CAEQ,OACN,SAAU,EAAI,WAAW,QAAQ,EACjC,UAAW,EACX,OAAQ,CAAE,GAAG,EAAS,OAAQ,GAAG,EAAQ,GAAG,EAAK,MAAO,CACzD,EALM,EAAK,EAKX,CACF,CACE,EAVK,CAUL,CACN,CACM,CAAA,CACT,CAAA,CAAA,CAEN"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{renderIcon as t}from"../utils/renderIcon.mjs";import n from"../virtualList/virtualList.mjs";import{flattenTree as r}from"./flattenTree.mjs";import i from"./tree.module.mjs";import{useEffect as a,useRef as o,useState as s}from"react";import c from"classnames";import{faChevronRight as l}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var f=[];function p(p){let{nodes:m,expandedKeys:h,defaultExpandedKeys:g=f,onExpandedChange:_=()=>{},selectedKey:v,defaultSelectedKey:y,onSelect:b=()=>{},expandOnSelect:x=!0,indent:S=20,toggleIcon:C=l,height:w,estimatedRowHeight:T=32,emptyLabel:ee=`Nothing here`,disabled:E=!1,"aria-label":D=`Tree`,className:O,style:k,classNames:A,styles:j,...M}=e(`Tree`,p),N=o(new Map),P=o(null),F=o(null),I=w!==void 0,L=h!==void 0,[R,z]=s(g),B=L?h:R,V=v!==void 0,[H,U]=s(y??null),W=V?v:H,G=r(m,B),K=Math.max(0,G.findIndex(e=>e.node.key===W)),q=G[K]?.node.key;function J(e){L||z(e),_(e)}function Y(e){J(B.includes(e)?B.filter(t=>t!==e):[...B,e])}function X(e){E||e.node.disabled||(V||U(e.node.key),b(e.node.key,e.node),x&&e.isBranch&&Y(e.node.key))}function Z(e){let t=G[e]?.node.key;if(t===void 0)return;let n=N.current.get(t);if(n){n.focus();return}F.current=t,P.current?.scrollToIndex(e,{align:`center`})}a(()=>{let e=F.current;if(e===null)return;let t=N.current.get(e);t&&(t.focus(),F.current=null)});function Q(e,t,n){if(!E)switch(e.key){case`ArrowDown`:e.preventDefault(),Z(Math.min(n+1,G.length-1));break;case`ArrowUp`:e.preventDefault(),Z(Math.max(n-1,0));break;case`ArrowRight`:if(e.preventDefault(),!t.isBranch)break;t.isExpanded?Z(n+1):Y(t.node.key);break;case`ArrowLeft`:{if(e.preventDefault(),t.isBranch&&t.isExpanded){Y(t.node.key);break}let n=G.findIndex(e=>e.node.key===t.parentKey);n>=0&&Z(n);break}case`Home`:e.preventDefault(),Z(0);break;case`End`:e.preventDefault(),Z(G.length-1);break;case`Enter`:case` `:e.preventDefault(),X(t)}}function $(e,n){let{node:r,level:a,isBranch:o,isExpanded:s}=e,l=r.key===W,f=E||r.disabled;return d(`div`,{ref:e=>{e?N.current.set(r.key,e):N.current.delete(r.key)},role:`treeitem`,"aria-level":a+1,"aria-setsize":e.setSize,"aria-posinset":e.posInSet,"aria-expanded":o?s:void 0,"aria-selected":l,"aria-disabled":f||void 0,tabIndex:r.key===q&&!f?0:-1,className:c(i.treeNode,l&&i.treeNodeSelected,f&&i.treeNodeDisabled,A?.node),style:{paddingLeft:a*S,...j?.node},onClick:()=>X(e),onKeyDown:t=>Q(t,e,n),children:[u(`span`,{className:c(i.treeToggle,s&&i.treeToggleOpen,!o&&i.treeToggleHidden,A?.toggle),style:j?.toggle,"aria-hidden":`true`,onClick:e=>{e.stopPropagation(),!f&&o&&Y(r.key)},children:o&&t(C)}),r.icon&&t(r.icon,{className:c(i.treeIcon,A?.icon),style:j?.icon}),u(`span`,{className:c(i.treeLabel,A?.label),style:j?.label,children:r.label})]},r.key)}return u(`div`,{...M,role:`tree`,"aria-label":D,"aria-disabled":E||void 0,tabIndex:I&&!E?0:void 0,onFocus:e=>{e.target===e.currentTarget&&Z(K)},className:c(i.tree,E&&i.treeDisabled,A?.root,O),style:{...k,...j?.root},children:G.length===0?u(`div`,{className:c(i.treeEmpty,A?.empty),style:j?.empty,children:ee}):I?u(n,{ref:P,items:G,height:w,estimatedRowHeight:T,getItemKey:e=>e.node.key,getItemDepth:e=>e.level,ariaRoles:{container:`none`,row:`none`},keyboardNavigation:!1,renderRow:$}):G.map($)})}export{p as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import r from"../virtualList/virtualList.mjs";import{flattenTree as i}from"./flattenTree.mjs";import a from"./tree.module.mjs";import{useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{faChevronRight as u}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var ee=[],p={empty:`Nothing here`};function m(m){let{nodes:h,expandedKeys:g,defaultExpandedKeys:_=ee,onExpandedChange:v=()=>{},selectedKey:y,defaultSelectedKey:te,onSelect:b=()=>{},expandOnSelect:x=!0,indent:S=20,toggleIcon:C=u,height:w,estimatedRowHeight:T=32,labels:E,disabled:D=!1,"aria-label":O=`Tree`,className:k,style:ne,classNames:A,styles:j,...M}=e(`Tree`,m),N=t(`Tree`,E,p),P=s(new Map),F=s(null),I=s(null),L=w!==void 0,R=g!==void 0,[z,B]=c(_),V=R?g:z,H=y!==void 0,[U,W]=c(te??null),G=H?y:U,K=i(h,V),q=Math.max(0,K.findIndex(e=>e.node.key===G)),J=K[q]?.node.key;function Y(e){R||B(e),v(e)}function X(e){Y(V.includes(e)?V.filter(t=>t!==e):[...V,e])}function Z(e){D||e.node.disabled||(H||W(e.node.key),b(e.node.key,e.node),x&&e.isBranch&&X(e.node.key))}function Q(e){let t=K[e]?.node.key;if(t===void 0)return;let n=P.current.get(t);if(n){n.focus();return}I.current=t,F.current?.scrollToIndex(e,{align:`center`})}o(()=>{let e=I.current;if(e===null)return;let t=P.current.get(e);t&&(t.focus(),I.current=null)});function re(e,t,n){if(!D)switch(e.key){case`ArrowDown`:e.preventDefault(),Q(Math.min(n+1,K.length-1));break;case`ArrowUp`:e.preventDefault(),Q(Math.max(n-1,0));break;case`ArrowRight`:if(e.preventDefault(),!t.isBranch)break;t.isExpanded?Q(n+1):X(t.node.key);break;case`ArrowLeft`:{if(e.preventDefault(),t.isBranch&&t.isExpanded){X(t.node.key);break}let n=K.findIndex(e=>e.node.key===t.parentKey);n>=0&&Q(n);break}case`Home`:e.preventDefault(),Q(0);break;case`End`:e.preventDefault(),Q(K.length-1);break;case`Enter`:case` `:e.preventDefault(),Z(t)}}function $(e,t){let{node:r,level:i,isBranch:o,isExpanded:s}=e,c=r.key===G,u=D||r.disabled;return f(`div`,{ref:e=>{e?P.current.set(r.key,e):P.current.delete(r.key)},role:`treeitem`,"aria-level":i+1,"aria-setsize":e.setSize,"aria-posinset":e.posInSet,"aria-expanded":o?s:void 0,"aria-selected":c,"aria-disabled":u||void 0,tabIndex:r.key===J&&!u?0:-1,className:l(a.treeNode,c&&a.treeNodeSelected,u&&a.treeNodeDisabled,A?.node),style:{paddingLeft:i*S,...j?.node},onClick:()=>Z(e),onKeyDown:n=>re(n,e,t),children:[d(`span`,{className:l(a.treeToggle,s&&a.treeToggleOpen,!o&&a.treeToggleHidden,A?.toggle),style:j?.toggle,"aria-hidden":`true`,onClick:e=>{e.stopPropagation(),!u&&o&&X(r.key)},children:o&&n(C)}),r.icon&&n(r.icon,{className:l(a.treeIcon,A?.icon),style:j?.icon}),d(`span`,{className:l(a.treeLabel,A?.label),style:j?.label,children:r.label})]},r.key)}return d(`div`,{...M,role:`tree`,"aria-label":O,"aria-disabled":D||void 0,tabIndex:L&&!D?0:void 0,onFocus:e=>{e.target===e.currentTarget&&Q(q)},className:l(a.tree,D&&a.treeDisabled,A?.root,k),style:{...ne,...j?.root},children:K.length===0?d(`div`,{className:l(a.treeEmpty,A?.empty),style:j?.empty,children:N.empty}):L?d(r,{ref:F,items:K,height:w,estimatedRowHeight:T,getItemKey:e=>e.node.key,getItemDepth:e=>e.level,ariaRoles:{container:`none`,row:`none`},keyboardNavigation:!1,renderRow:$}):K.map($)})}export{m as default};
2
2
  //# sourceMappingURL=tree.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree.mjs","names":[],"sources":["../../../../package/common/tree/tree.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport VirtualList from 'components/common/virtualList';\nimport type { VirtualListHandle } from 'components/common/virtualList';\nimport { useComponentDefaults } from '../configProvider';\nimport { renderIcon } from '../utils/renderIcon';\nimport { flattenTree } from './flattenTree';\nimport type { FlatTreeNode, TreeProps, TreeValue } from './tree.types';\n\nimport styles from './tree.module.pcss';\n\nconst EMPTY_KEYS: TreeValue[] = [];\n\nfunction Tree(props: TreeProps): ReactElement {\n const {\n nodes,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys = EMPTY_KEYS,\n onExpandedChange = () => {},\n selectedKey: controlledSelected,\n defaultSelectedKey,\n onSelect = () => {},\n expandOnSelect = true,\n indent = 20,\n toggleIcon = faChevronRight,\n height,\n estimatedRowHeight = 32,\n emptyLabel = 'Nothing here',\n disabled = false,\n 'aria-label': ariaLabel = 'Tree',\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Tree', props);\n\n const nodeRefs = useRef(new Map<TreeValue, HTMLDivElement>());\n const listRef = useRef<VirtualListHandle>(null);\n const pendingFocusRef = useRef<TreeValue | null>(null);\n const isWindowed = height !== undefined;\n\n const isExpandedControlled = controlledExpanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<TreeValue[]>(defaultExpandedKeys);\n const expandedKeys = isExpandedControlled ? controlledExpanded : internalExpanded;\n\n const isSelectedControlled = controlledSelected !== undefined;\n const [internalSelected, setInternalSelected] = useState<TreeValue | null>(defaultSelectedKey ?? null);\n const selectedKey = isSelectedControlled ? controlledSelected : internalSelected;\n\n const visible = flattenTree(nodes, expandedKeys);\n\n // Windowed, the tab stop sits on the container instead of this row: a roving tabindex on a row\n // scrolled out of the window would leave the tree with no tab stop at all.\n const activeIndex = Math.max(\n 0,\n visible.findIndex((entry) => entry.node.key === selectedKey),\n );\n const activeKey = visible[activeIndex]?.node.key;\n\n function setExpanded(next: TreeValue[]) {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange(next);\n }\n\n function toggle(key: TreeValue) {\n setExpanded(expandedKeys.includes(key) ? expandedKeys.filter((k) => k !== key) : [...expandedKeys, key]);\n }\n\n function select(entry: FlatTreeNode) {\n if (disabled || entry.node.disabled) return;\n if (!isSelectedControlled) setInternalSelected(entry.node.key);\n onSelect(entry.node.key, entry.node);\n if (expandOnSelect && entry.isBranch) toggle(entry.node.key);\n }\n\n function focusAt(index: number) {\n const key = visible[index]?.node.key;\n if (key === undefined) return;\n\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n return;\n }\n\n // Outside the window, so it has to be scrolled in before it exists to receive focus.\n pendingFocusRef.current = key;\n listRef.current?.scrollToIndex(index, { align: 'center' });\n }\n\n useEffect(() => {\n const key = pendingFocusRef.current;\n if (key === null) return;\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n pendingFocusRef.current = null;\n }\n });\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>, entry: FlatTreeNode, index: number) {\n if (disabled) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusAt(Math.min(index + 1, visible.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusAt(Math.max(index - 1, 0));\n break;\n case 'ArrowRight':\n event.preventDefault();\n if (!entry.isBranch) break;\n if (entry.isExpanded) focusAt(index + 1);\n else toggle(entry.node.key);\n break;\n case 'ArrowLeft': {\n event.preventDefault();\n if (entry.isBranch && entry.isExpanded) {\n toggle(entry.node.key);\n break;\n }\n const parentIndex = visible.findIndex((e) => e.node.key === entry.parentKey);\n if (parentIndex >= 0) focusAt(parentIndex);\n break;\n }\n case 'Home':\n event.preventDefault();\n focusAt(0);\n break;\n case 'End':\n event.preventDefault();\n focusAt(visible.length - 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n select(entry);\n break;\n default:\n break;\n }\n }\n\n function renderNode(entry: FlatTreeNode, index: number) {\n const { node, level, isBranch, isExpanded } = entry;\n const isSelected = node.key === selectedKey;\n const isDisabled = disabled || node.disabled;\n\n return (\n <div\n key={node.key}\n ref={(el) => {\n if (el) nodeRefs.current.set(node.key, el);\n else nodeRefs.current.delete(node.key);\n }}\n role='treeitem'\n aria-level={level + 1}\n aria-setsize={entry.setSize}\n aria-posinset={entry.posInSet}\n aria-expanded={isBranch ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-disabled={isDisabled || undefined}\n tabIndex={node.key === activeKey && !isDisabled ? 0 : -1}\n className={cx(\n styles.treeNode,\n isSelected && styles.treeNodeSelected,\n isDisabled && styles.treeNodeDisabled,\n classNames?.node,\n )}\n style={{ paddingLeft: level * indent, ...slotStyles?.node }}\n onClick={() => select(entry)}\n onKeyDown={(event) => handleKeyDown(event, entry, index)}\n >\n <span\n className={cx(\n styles.treeToggle,\n isExpanded && styles.treeToggleOpen,\n !isBranch && styles.treeToggleHidden,\n classNames?.toggle,\n )}\n style={slotStyles?.toggle}\n aria-hidden='true'\n onClick={(event) => {\n event.stopPropagation();\n if (!isDisabled && isBranch) toggle(node.key);\n }}\n >\n {isBranch && renderIcon(toggleIcon)}\n </span>\n\n {node.icon &&\n renderIcon(node.icon, {\n className: cx(styles.treeIcon, classNames?.icon),\n style: slotStyles?.icon,\n })}\n\n <span className={cx(styles.treeLabel, classNames?.label)} style={slotStyles?.label}>\n {node.label}\n </span>\n </div>\n );\n }\n\n return (\n <div\n {...rest}\n role='tree'\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n tabIndex={isWindowed && !disabled ? 0 : undefined}\n onFocus={(event) => {\n if (event.target === event.currentTarget) focusAt(activeIndex);\n }}\n className={cx(styles.tree, disabled && styles.treeDisabled, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {visible.length === 0 ? (\n <div className={cx(styles.treeEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {emptyLabel}\n </div>\n ) : isWindowed ? (\n <VirtualList\n ref={listRef}\n items={visible}\n height={height}\n estimatedRowHeight={estimatedRowHeight}\n getItemKey={(entry) => entry.node.key}\n getItemDepth={(entry) => entry.level}\n ariaRoles={{ container: 'none', row: 'none' }}\n // Tree owns the keyboard: its rows carry the roving tabindex and their\n // own key handling, and a second tab stop here would sit inside it.\n keyboardNavigation={false}\n renderRow={renderNode}\n />\n ) : (\n visible.map(renderNode)\n )}\n </div>\n );\n}\n\nexport default Tree;\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree.mjs","names":[],"sources":["../../../../package/common/tree/tree.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport VirtualList from 'components/common/virtualList';\nimport type { VirtualListHandle } from 'components/common/virtualList';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { renderIcon } from '../utils/renderIcon';\nimport { flattenTree } from './flattenTree';\nimport type { FlatTreeNode, TreeLabels, TreeProps, TreeValue } from './tree.types';\n\nimport styles from './tree.module.pcss';\n\nconst EMPTY_KEYS: TreeValue[] = [];\n\nconst DEFAULT_LABELS: Required<TreeLabels> = {\n empty: 'Nothing here',\n};\n\nfunction Tree(props: TreeProps): ReactElement {\n const {\n nodes,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys = EMPTY_KEYS,\n onExpandedChange = () => {},\n selectedKey: controlledSelected,\n defaultSelectedKey,\n onSelect = () => {},\n expandOnSelect = true,\n indent = 20,\n toggleIcon = faChevronRight,\n height,\n estimatedRowHeight = 32,\n labels,\n disabled = false,\n 'aria-label': ariaLabel = 'Tree',\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Tree', props);\n const text = useLabels('Tree', labels, DEFAULT_LABELS);\n\n const nodeRefs = useRef(new Map<TreeValue, HTMLDivElement>());\n const listRef = useRef<VirtualListHandle>(null);\n const pendingFocusRef = useRef<TreeValue | null>(null);\n const isWindowed = height !== undefined;\n\n const isExpandedControlled = controlledExpanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<TreeValue[]>(defaultExpandedKeys);\n const expandedKeys = isExpandedControlled ? controlledExpanded : internalExpanded;\n\n const isSelectedControlled = controlledSelected !== undefined;\n const [internalSelected, setInternalSelected] = useState<TreeValue | null>(defaultSelectedKey ?? null);\n const selectedKey = isSelectedControlled ? controlledSelected : internalSelected;\n\n const visible = flattenTree(nodes, expandedKeys);\n\n // Windowed, the tab stop sits on the container instead of this row: a roving tabindex on a row\n // scrolled out of the window would leave the tree with no tab stop at all.\n const activeIndex = Math.max(\n 0,\n visible.findIndex((entry) => entry.node.key === selectedKey),\n );\n const activeKey = visible[activeIndex]?.node.key;\n\n function setExpanded(next: TreeValue[]) {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange(next);\n }\n\n function toggle(key: TreeValue) {\n setExpanded(expandedKeys.includes(key) ? expandedKeys.filter((k) => k !== key) : [...expandedKeys, key]);\n }\n\n function select(entry: FlatTreeNode) {\n if (disabled || entry.node.disabled) return;\n if (!isSelectedControlled) setInternalSelected(entry.node.key);\n onSelect(entry.node.key, entry.node);\n if (expandOnSelect && entry.isBranch) toggle(entry.node.key);\n }\n\n function focusAt(index: number) {\n const key = visible[index]?.node.key;\n if (key === undefined) return;\n\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n return;\n }\n\n // Outside the window, so it has to be scrolled in before it exists to receive focus.\n pendingFocusRef.current = key;\n listRef.current?.scrollToIndex(index, { align: 'center' });\n }\n\n useEffect(() => {\n const key = pendingFocusRef.current;\n if (key === null) return;\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n pendingFocusRef.current = null;\n }\n });\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>, entry: FlatTreeNode, index: number) {\n if (disabled) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusAt(Math.min(index + 1, visible.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusAt(Math.max(index - 1, 0));\n break;\n case 'ArrowRight':\n event.preventDefault();\n if (!entry.isBranch) break;\n if (entry.isExpanded) focusAt(index + 1);\n else toggle(entry.node.key);\n break;\n case 'ArrowLeft': {\n event.preventDefault();\n if (entry.isBranch && entry.isExpanded) {\n toggle(entry.node.key);\n break;\n }\n const parentIndex = visible.findIndex((e) => e.node.key === entry.parentKey);\n if (parentIndex >= 0) focusAt(parentIndex);\n break;\n }\n case 'Home':\n event.preventDefault();\n focusAt(0);\n break;\n case 'End':\n event.preventDefault();\n focusAt(visible.length - 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n select(entry);\n break;\n default:\n break;\n }\n }\n\n function renderNode(entry: FlatTreeNode, index: number) {\n const { node, level, isBranch, isExpanded } = entry;\n const isSelected = node.key === selectedKey;\n const isDisabled = disabled || node.disabled;\n\n return (\n <div\n key={node.key}\n ref={(el) => {\n if (el) nodeRefs.current.set(node.key, el);\n else nodeRefs.current.delete(node.key);\n }}\n role='treeitem'\n aria-level={level + 1}\n aria-setsize={entry.setSize}\n aria-posinset={entry.posInSet}\n aria-expanded={isBranch ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-disabled={isDisabled || undefined}\n tabIndex={node.key === activeKey && !isDisabled ? 0 : -1}\n className={cx(\n styles.treeNode,\n isSelected && styles.treeNodeSelected,\n isDisabled && styles.treeNodeDisabled,\n classNames?.node,\n )}\n style={{ paddingLeft: level * indent, ...slotStyles?.node }}\n onClick={() => select(entry)}\n onKeyDown={(event) => handleKeyDown(event, entry, index)}\n >\n <span\n className={cx(\n styles.treeToggle,\n isExpanded && styles.treeToggleOpen,\n !isBranch && styles.treeToggleHidden,\n classNames?.toggle,\n )}\n style={slotStyles?.toggle}\n aria-hidden='true'\n onClick={(event) => {\n event.stopPropagation();\n if (!isDisabled && isBranch) toggle(node.key);\n }}\n >\n {isBranch && renderIcon(toggleIcon)}\n </span>\n\n {node.icon &&\n renderIcon(node.icon, {\n className: cx(styles.treeIcon, classNames?.icon),\n style: slotStyles?.icon,\n })}\n\n <span className={cx(styles.treeLabel, classNames?.label)} style={slotStyles?.label}>\n {node.label}\n </span>\n </div>\n );\n }\n\n return (\n <div\n {...rest}\n role='tree'\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n tabIndex={isWindowed && !disabled ? 0 : undefined}\n onFocus={(event) => {\n if (event.target === event.currentTarget) focusAt(activeIndex);\n }}\n className={cx(styles.tree, disabled && styles.treeDisabled, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {visible.length === 0 ? (\n <div className={cx(styles.treeEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {text.empty}\n </div>\n ) : isWindowed ? (\n <VirtualList\n ref={listRef}\n items={visible}\n height={height}\n estimatedRowHeight={estimatedRowHeight}\n getItemKey={(entry) => entry.node.key}\n getItemDepth={(entry) => entry.level}\n ariaRoles={{ container: 'none', row: 'none' }}\n // Tree owns the keyboard: its rows carry the roving tabindex and their\n // own key handling, and a second tab stop here would sit inside it.\n keyboardNavigation={false}\n renderRow={renderNode}\n />\n ) : (\n visible.map(renderNode)\n )}\n </div>\n );\n}\n\nexport default Tree;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"../loading/spinnerLoading/index.mjs";import t from"../checkbox/checkbox.mjs";import n from"./virtualList.module.mjs";import"./virtualList.utils.mjs";import ee from"./virtualRow.mjs";import r from"./virtualListHeader.mjs";import{useVirtualWindow as i}from"./useVirtualWindow.mjs";import{useSelection as a}from"./useSelection.mjs";import{useColumns as o}from"./useColumns.mjs";import{useRowDrag as te}from"./useRowDrag.mjs";import{useSorting as ne}from"./useSorting.mjs";import{useColumnResize as re}from"./useColumnResize.mjs";import{useRowNavigation as ie}from"./useRowNavigation.mjs";import s,{useCallback as c,useEffect as ae,useId as oe,useImperativeHandle as se,useMemo as l,useRef as ce}from"react";import u from"classnames";import{Fragment as le,jsx as d,jsxs as f}from"react/jsx-runtime";function p({items:s,renderRow:p,ariaRoles:m,columns:h,height:ue=`100%`,estimatedRowHeight:de=40,overscan:fe=3,rowGap:pe=0,rowPadding:g,selectedKey:_,getItemKey:v,onRowClick:y,keyboardNavigation:b=!0,visibleColumnKeys:me,onVisibleColumnsChange:he,persistColumnsKey:ge,resizableColumns:_e=!1,columnWidths:ve,onColumnWidthsChange:ye,resetColumnWidthsLabel:be=`Reset column widths`,sort:xe,defaultSort:Se,onSortChange:Ce,showColumnToggle:we,onLoadMore:Te,loadMoreThreshold:Ee=100,isLoading:x=!1,multiSelect:S=!1,selectedKeys:De,onSelectionChange:Oe,reorderable:C=!1,onReorder:ke,longPressDelay:Ae=400,treeReorder:w=!1,getItemDepth:T,isGroup:E,onTreeDrop:je,treeIndentPx:Me=24,dragHandle:Ne=!1,showDivider:Pe=!0,rowHover:Fe=!0,className:Ie,style:Le,classNames:D,styles:O,...Re},ze){let{rows:k,effectiveSort:Be,isSorted:A,handleHeaderSort:Ve}=ne({items:s,columns:h,sort:xe,defaultSort:Se,onSortChange:Ce}),j=c((e,t)=>v?v(e,t):t,[v]),M=l(()=>k.map((e,t)=>j(e,t)),[k,j]),He=l(()=>T?k.map((e,t)=>T(e,t)):[],[k,T]),Ue=c(e=>E?E(k[e],e):!1,[E,k]),N=i({items:k,keys:M,getItemKey:v,estimatedRowHeight:de,rowGap:pe,overscan:fe,onLoadMore:Te,loadMoreThreshold:Ee,isLoading:x}),{rootRef:P,headerRef:F,rowObserver:We,keysRef:Ge,offsets:I,totalHeight:Ke,startIndex:L,endIndex:R}=N,z=ce([]),B=re({columns:h,visibleColumnsRef:z,resizableColumns:_e,columnWidths:ve,onColumnWidthsChange:ye,persistColumnsKey:ge,rootRef:P}),V=a({items:k,getKey:j,multiSelect:S,selectedKeys:De,onSelectionChange:Oe}),{effectiveSelectedKeys:H}=V,U=o({columns:h,items:k,multiSelect:S,visibleColumnKeys:me,onVisibleColumnsChange:he,persistColumnsKey:ge,showColumnToggle:we,userWidths:B.widths,isFrozen:B.isFrozen,rootRef:P,startIndex:L,endIndex:R,containerHeight:N.containerHeight,containerWidth:N.containerWidth}),{hasColumns:W,visibleColumns:G,columnTemplate:qe,widthVars:Je,shouldShowToggle:Ye,recalculateColumns:K}=U;z.current=G,se(ze,()=>({...N.scrollApi,recalculateColumns:K,resetColumnWidths:B.reset}),[N.scrollApi,K,B.reset]);let q=A&&(C||w);ae(()=>{q&&console.warn(`VirtualList: row reordering is disabled while the list is sorted. Clear the sort to drag rows.`)},[q]);let J=te({reorderable:C&&!A,treeReorder:w&&!A,onReorder:ke,onTreeDrop:je,longPressDelay:Ae,dragHandle:Ne,treeIndentPx:Me,keys:M,depths:He,isGroupAt:Ue,rootRef:P,keysRef:Ge}),Xe=oe(),Y=e=>`${Xe}-row-${e}`,X=ie({enabled:b,rowCount:k.length,offsets:I,rootRef:P,headerRef:F,scrollToIndex:N.scrollApi.scrollToIndex,initialIndex:_==null?0:Math.max(0,M.indexOf(_)),multiSelect:S,onActivate:y&&(e=>y(k[e],e)),onToggleSelect:e=>V.handleRowSelect(M[e])}),Ze=typeof g==`number`?`${g}px`:g,Z=e=>{let r=k[e],i=j(r,e),a=_!=null&&i===_||H.has(i),o=J.getRowDragProps(e,i);return d(ee,{id:Y(e),index:e,top:I[e],padding:Ze,columnTemplate:qe,isSelected:a,isActive:e===X.activeIndex,manageTabStops:b,isEntered:e===X.enteredIndex,activeClassName:D?.activeRow,activeStyle:O?.activeRow,showDivider:Pe,hover:Fe,onClick:()=>{J.consumeSuppressedClick()||(X.setActiveIndex(e),y?.(r,e))},observer:We,ariaRowIndex:W?e+2:void 0,ariaPosInSet:W?void 0:e+1,ariaSetSize:W?void 0:k.length,rowRole:m?.row??(W?`row`:`listitem`),reserveToggleGutter:Ye,...o,dropIndicatorClassName:D?.dropIndicator,dropIndicatorStyle:O?.dropIndicator,rowClassName:D?.row,rowStyle:O?.row,children:W?f(le,{children:[S&&d(`div`,{className:u(n.virtualListSelectCell,D?.selectCell),style:O?.selectCell,role:`gridcell`,onClick:e=>e.stopPropagation(),children:d(t,{selected:H.has(i),onToggle:()=>V.handleRowSelect(i),"aria-label":`Select row`,tabIndex:-1})}),G.map(t=>d(`div`,{className:u(n.virtualListCell,D?.cell),style:O?.cell,role:`gridcell`,"data-col-key":t.key,"data-fit-key":t.width.type===`fit`?t.key:void 0,children:t.renderCell(r,e)},t.key))]}):p?.(r,e)},i)},Q=[];for(let e=L;e<=R;e++)Q.push(Z(e));let $=J.draggingKey==null?-1:M.indexOf(J.draggingKey);return $>=0&&($<L||$>R)&&Q.push(Z($)),X.enteredIndex>=0&&(X.enteredIndex<L||X.enteredIndex>R)&&Q.push(Z(X.enteredIndex)),f(`div`,{...Re,...X.containerProps,ref:P,className:u(n.virtualList,J.draggingKey!=null&&n.virtualListReordering,B.isResizing&&n.virtualListResizing,Ie,D?.root),style:{height:ue,...Je,...Le,...O?.root},onScroll:N.handleScroll,role:m?.container??(W?`grid`:`list`),"aria-rowcount":W?k.length+1:void 0,"aria-activedescendant":X.activeIndex>=0&&(m?.container??(W?`grid`:`list`))!==`list`?Y(X.activeIndex):void 0,children:[W&&d(r,{headerRef:F,columns:h,cols:U,resize:B,sort:Be,onSort:Ve,multiSelect:S,allSelected:V.allSelected,someSelected:V.someSelected,onSelectAll:V.handleSelectAll,resetColumnWidthsLabel:be,classNames:D,styles:O}),x?d(`div`,{className:n.virtualListLoadingFull,children:d(e,{className:n.virtualListSpinner})}):d(`div`,{className:u(n.virtualListBody,D?.body),style:{height:Ke,...O?.body},children:Q}),N.showLoadMoreSpinner&&d(`div`,{className:u(n.virtualListLoadingIndicator,D?.loadingIndicator),style:O?.loadingIndicator,children:d(e,{className:n.virtualListSpinner})})]})}var m=s.forwardRef(p);export{m as default};
1
+ import{useLabels as e}from"../configProvider/useLabels.mjs";import t from"../loading/spinnerLoading/index.mjs";import n from"../checkbox/checkbox.mjs";import r from"./virtualList.module.mjs";import"./virtualList.utils.mjs";import ee from"./virtualRow.mjs";import i from"./virtualListHeader.mjs";import{useVirtualWindow as a}from"./useVirtualWindow.mjs";import{useSelection as o}from"./useSelection.mjs";import{useColumns as te}from"./useColumns.mjs";import{useRowDrag as ne}from"./useRowDrag.mjs";import{useSorting as re}from"./useSorting.mjs";import{useColumnResize as ie}from"./useColumnResize.mjs";import{useRowNavigation as ae}from"./useRowNavigation.mjs";import oe,{useCallback as s,useEffect as se,useId as ce,useImperativeHandle as le,useMemo as c,useRef as ue}from"react";import l from"classnames";import{Fragment as de,jsx as u,jsxs as d}from"react/jsx-runtime";var fe={selectRow:`Select row`,selectAllRows:`Select all rows`,toggleColumns:`Toggle column visibility`,columnsHidden:e=>`${e} columns hidden`,resetColumnWidths:`Reset column widths`};function f({items:oe,renderRow:f,ariaRoles:p,columns:m,height:pe=`100%`,estimatedRowHeight:me=40,overscan:he=3,rowGap:ge=0,rowPadding:h,selectedKey:g,getItemKey:_,onRowClick:v,keyboardNavigation:y=!0,visibleColumnKeys:_e,onVisibleColumnsChange:ve,persistColumnsKey:b,resizableColumns:ye=!1,columnWidths:be,onColumnWidthsChange:xe,labels:Se,sort:Ce,defaultSort:we,onSortChange:Te,showColumnToggle:Ee,onLoadMore:De,loadMoreThreshold:Oe=100,isLoading:x=!1,multiSelect:S=!1,selectedKeys:ke,onSelectionChange:Ae,reorderable:C=!1,onReorder:je,longPressDelay:Me=400,treeReorder:w=!1,getItemDepth:T,isGroup:E,onTreeDrop:Ne,treeIndentPx:Pe=24,dragHandle:Fe=!1,showDivider:Ie=!0,rowHover:Le=!0,className:Re,style:ze,classNames:D,styles:O,...Be},Ve){let k=e(`VirtualList`,Se,fe),{rows:A,effectiveSort:He,isSorted:j,handleHeaderSort:Ue}=re({items:oe,columns:m,sort:Ce,defaultSort:we,onSortChange:Te}),M=s((e,t)=>_?_(e,t):t,[_]),N=c(()=>A.map((e,t)=>M(e,t)),[A,M]),We=c(()=>T?A.map((e,t)=>T(e,t)):[],[A,T]),Ge=s(e=>E?E(A[e],e):!1,[E,A]),P=a({items:A,keys:N,getItemKey:_,estimatedRowHeight:me,rowGap:ge,overscan:he,onLoadMore:De,loadMoreThreshold:Oe,isLoading:x}),{rootRef:F,headerRef:I,rowObserver:Ke,keysRef:qe,offsets:L,totalHeight:Je,startIndex:R,endIndex:z}=P,B=ue([]),V=ie({columns:m,visibleColumnsRef:B,resizableColumns:ye,columnWidths:be,onColumnWidthsChange:xe,persistColumnsKey:b,rootRef:F}),H=o({items:A,getKey:M,multiSelect:S,selectedKeys:ke,onSelectionChange:Ae}),{effectiveSelectedKeys:U}=H,W=te({columns:m,items:A,multiSelect:S,visibleColumnKeys:_e,onVisibleColumnsChange:ve,persistColumnsKey:b,showColumnToggle:Ee,userWidths:V.widths,isFrozen:V.isFrozen,rootRef:F,startIndex:R,endIndex:z,containerHeight:P.containerHeight,containerWidth:P.containerWidth}),{hasColumns:G,visibleColumns:K,columnTemplate:Ye,widthVars:Xe,shouldShowToggle:Ze,recalculateColumns:q}=W;B.current=K,le(Ve,()=>({...P.scrollApi,recalculateColumns:q,resetColumnWidths:V.reset}),[P.scrollApi,q,V.reset]);let J=j&&(C||w);se(()=>{J&&console.warn(`VirtualList: row reordering is disabled while the list is sorted. Clear the sort to drag rows.`)},[J]);let Y=ne({reorderable:C&&!j,treeReorder:w&&!j,onReorder:je,onTreeDrop:Ne,longPressDelay:Me,dragHandle:Fe,treeIndentPx:Pe,keys:N,depths:We,isGroupAt:Ge,rootRef:F,keysRef:qe}),Qe=ce(),$e=e=>`${Qe}-row-${e}`,X=ae({enabled:y,rowCount:A.length,offsets:L,rootRef:F,headerRef:I,scrollToIndex:P.scrollApi.scrollToIndex,initialIndex:g==null?0:Math.max(0,N.indexOf(g)),multiSelect:S,onActivate:v&&(e=>v(A[e],e)),onToggleSelect:e=>H.handleRowSelect(N[e])}),et=typeof h==`number`?`${h}px`:h,Z=e=>{let t=A[e],i=M(t,e),a=g!=null&&i===g||U.has(i),o=Y.getRowDragProps(e,i);return u(ee,{id:$e(e),index:e,top:L[e],padding:et,columnTemplate:Ye,isSelected:a,isActive:e===X.activeIndex,manageTabStops:y,isEntered:e===X.enteredIndex,activeClassName:D?.activeRow,activeStyle:O?.activeRow,showDivider:Ie,hover:Le,onClick:()=>{Y.consumeSuppressedClick()||(X.setActiveIndex(e),v?.(t,e))},observer:Ke,ariaRowIndex:G?e+2:void 0,ariaPosInSet:G?void 0:e+1,ariaSetSize:G?void 0:A.length,rowRole:p?.row??(G?`row`:`listitem`),reserveToggleGutter:Ze,...o,dropIndicatorClassName:D?.dropIndicator,dropIndicatorStyle:O?.dropIndicator,rowClassName:D?.row,rowStyle:O?.row,children:G?d(de,{children:[S&&u(`div`,{className:l(r.virtualListSelectCell,D?.selectCell),style:O?.selectCell,role:`gridcell`,onClick:e=>e.stopPropagation(),children:u(n,{selected:U.has(i),onToggle:()=>H.handleRowSelect(i),"aria-label":k.selectRow,tabIndex:-1})}),K.map(n=>u(`div`,{className:l(r.virtualListCell,D?.cell),style:O?.cell,role:`gridcell`,"data-col-key":n.key,"data-fit-key":n.width.type===`fit`?n.key:void 0,children:n.renderCell(t,e)},n.key))]}):f?.(t,e)},i)},Q=[];for(let e=R;e<=z;e++)Q.push(Z(e));let $=Y.draggingKey==null?-1:N.indexOf(Y.draggingKey);return $>=0&&($<R||$>z)&&Q.push(Z($)),X.enteredIndex>=0&&(X.enteredIndex<R||X.enteredIndex>z)&&Q.push(Z(X.enteredIndex)),d(`div`,{...Be,...X.containerProps,ref:F,className:l(r.virtualList,Y.draggingKey!=null&&r.virtualListReordering,V.isResizing&&r.virtualListResizing,Re,D?.root),style:{height:pe,...Xe,...ze,...O?.root},onScroll:P.handleScroll,role:p?.container??(G?`grid`:`list`),"aria-rowcount":G?A.length+1:void 0,"aria-activedescendant":X.activeIndex>=0&&(p?.container??(G?`grid`:`list`))!==`list`?$e(X.activeIndex):void 0,children:[G&&u(i,{headerRef:I,columns:m,cols:W,resize:V,sort:He,onSort:Ue,multiSelect:S,allSelected:H.allSelected,someSelected:H.someSelected,onSelectAll:H.handleSelectAll,labels:k,classNames:D,styles:O}),x?u(`div`,{className:r.virtualListLoadingFull,children:u(t,{className:r.virtualListSpinner})}):u(`div`,{className:l(r.virtualListBody,D?.body),style:{height:Je,...O?.body},children:Q}),P.showLoadMoreSpinner&&u(`div`,{className:l(r.virtualListLoadingIndicator,D?.loadingIndicator),style:O?.loadingIndicator,children:u(t,{className:r.virtualListSpinner})})]})}var p=oe.forwardRef(f);export{p as default};
2
2
  //# sourceMappingURL=virtualList.mjs.map