@lifesg/react-design-system 3.5.0-canary.6 → 3.5.0-canary.7

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 (83) hide show
  1. package/accordion/types.d.ts +7 -1
  2. package/cjs/external/dompurify/dist/purify.es.js +2 -2
  3. package/cjs/external/dompurify/dist/purify.es.js.map +1 -1
  4. package/cjs/input-group/input-group-list-addon.js +1 -1
  5. package/cjs/input-group/input-group-list-addon.js.map +1 -1
  6. package/cjs/input-range-select/input-range-select.js +1 -1
  7. package/cjs/input-range-select/input-range-select.js.map +1 -1
  8. package/cjs/input-select/input-select.js +1 -1
  9. package/cjs/input-select/input-select.js.map +1 -1
  10. package/cjs/navbar/navbar-items.js +1 -1
  11. package/cjs/navbar/navbar-items.js.map +1 -1
  12. package/cjs/navbar/navbar-items.styles.js +1 -1
  13. package/cjs/navbar/navbar-items.styles.js.map +1 -1
  14. package/cjs/otp-verification/thumbnail/email-thumbnail.js.map +1 -1
  15. package/cjs/otp-verification/thumbnail/phone-thumbnail.js.map +1 -1
  16. package/cjs/shared/dropdown-list/dropdown-list.js +1 -1
  17. package/cjs/shared/dropdown-list/dropdown-list.js.map +1 -1
  18. package/cjs/sidenav/sidenav-item.js +1 -1
  19. package/cjs/sidenav/sidenav-item.js.map +1 -1
  20. package/cjs/tab/tab-context-provider.js +2 -0
  21. package/cjs/tab/tab-context-provider.js.map +1 -0
  22. package/cjs/tab/tab-context.js +1 -1
  23. package/cjs/tab/tab-context.js.map +1 -1
  24. package/cjs/tab/tab-item.js +1 -1
  25. package/cjs/tab/tab-item.js.map +1 -1
  26. package/cjs/tab/tab-link-chain.js +1 -1
  27. package/cjs/tab/tab-link-chain.js.map +1 -1
  28. package/cjs/tab/tab-list-item.js +2 -0
  29. package/cjs/tab/tab-list-item.js.map +1 -0
  30. package/cjs/tab/tab-list.js +2 -0
  31. package/cjs/tab/tab-list.js.map +1 -0
  32. package/cjs/tab/tab-panel.js +2 -0
  33. package/cjs/tab/tab-panel.js.map +1 -0
  34. package/cjs/tab/tab.js +1 -1
  35. package/cjs/tab/tab.js.map +1 -1
  36. package/external/dompurify/dist/purify.es.js +2 -2
  37. package/external/dompurify/dist/purify.es.js.map +1 -1
  38. package/input-group/input-group-list-addon.js +1 -1
  39. package/input-group/input-group-list-addon.js.map +1 -1
  40. package/input-multi-select/types.d.ts +1 -1
  41. package/input-range-select/input-range-select.d.ts +1 -1
  42. package/input-range-select/input-range-select.js +1 -1
  43. package/input-range-select/input-range-select.js.map +1 -1
  44. package/input-select/input-select.d.ts +1 -1
  45. package/input-select/input-select.js +1 -1
  46. package/input-select/input-select.js.map +1 -1
  47. package/link-list/internal-types.d.ts +3 -3
  48. package/navbar/navbar-items.js +1 -1
  49. package/navbar/navbar-items.js.map +1 -1
  50. package/navbar/navbar-items.styles.d.ts +8 -8
  51. package/navbar/navbar-items.styles.js +1 -1
  52. package/navbar/navbar-items.styles.js.map +1 -1
  53. package/otp-verification/thumbnail/email-thumbnail.js.map +1 -1
  54. package/otp-verification/thumbnail/phone-thumbnail.js.map +1 -1
  55. package/package.json +1 -1
  56. package/shared/dropdown-list/dropdown-list.js +1 -1
  57. package/shared/dropdown-list/dropdown-list.js.map +1 -1
  58. package/shared/dropdown-list/types.d.ts +4 -1
  59. package/sidenav/sidenav-item.js +1 -1
  60. package/sidenav/sidenav-item.js.map +1 -1
  61. package/tab/tab-context-provider.d.ts +5 -0
  62. package/tab/tab-context-provider.js +2 -0
  63. package/tab/tab-context-provider.js.map +1 -0
  64. package/tab/tab-context.d.ts +5 -0
  65. package/tab/tab-context.js +1 -1
  66. package/tab/tab-context.js.map +1 -1
  67. package/tab/tab-item.js +1 -1
  68. package/tab/tab-item.js.map +1 -1
  69. package/tab/tab-link-chain.js +1 -1
  70. package/tab/tab-link-chain.js.map +1 -1
  71. package/tab/tab-list-item.d.ts +5 -0
  72. package/tab/tab-list-item.js +2 -0
  73. package/tab/tab-list-item.js.map +1 -0
  74. package/tab/tab-list.d.ts +5 -0
  75. package/tab/tab-list.js +2 -0
  76. package/tab/tab-list.js.map +1 -0
  77. package/tab/tab-panel.d.ts +5 -0
  78. package/tab/tab-panel.js +2 -0
  79. package/tab/tab-panel.js.map +1 -0
  80. package/tab/tab.d.ts +31 -0
  81. package/tab/tab.js +1 -1
  82. package/tab/tab.js.map +1 -1
  83. package/tab/types.d.ts +83 -1
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useContext as n,useRef as r}from"react";import{r as i}from"../external/react-responsive/dist/react-responsive.js";import{ThemeContext as o}from"styled-components";import{Breakpoint as l}from"../theme/index.js";import{TabContext as d}from"./tab-context.js";import{CustomFadeWrapper as a,Chain as c,ChainItem as s,ChainLink as u,LabelContainer as m,Label as f,BoldLabel as h}from"./tab-link-chain.style.js";const p=({controlledMode:p,"data-testid":v,onTabClick:g,fullWidthIndicatorLine:x,fadeColor:b})=>{const{setCurrentActiveIndex:$,currentActiveIndex:k,tabLinks:w}=n(d),C=n(o),y=l["md-max"]({theme:C}),j=i.useMediaQuery({maxWidth:y}),A=l["lg-max"]({theme:C}),I=r(null),L=r([]),D=r(null),R=e=>t=>{t.preventDefault(),t.stopPropagation(),p||$(e),g&&g(w[e].title,e)},W=e=>j&&e.length>20?`${e.substring(0,20)}...`:e;return e(a,{onResize:({content:e,wrapper:t})=>{e&&t&&window.innerWidth<=A&&I.current&&D.current&&(e.scrollLeft=I.current.getBoundingClientRect().left-D.current.getBoundingClientRect().left)},"data-testid":v,fadeColor:b,children:e(c,{role:"tablist",$fullWidthIndicatorLine:x,ref:D,children:w.map((({title:n,width:r,titleAddon:i},o)=>{const l=k===o;return e(s,{role:"none",$active:l,ref:l?I:null,$width:r,children:t(u,{role:"none",onClick:R(o),"data-testid":`${v}-link-${o}`,$reversed:"left"===(null==i?void 0:i.position),children:[t(m,{role:"none",children:[e(f,{$active:l,onClick:R(o),"aria-hidden":"true",children:W(n)}),e(h,{role:"tab",type:"button","aria-selected":l,tabIndex:l?0:-1,onKeyDown:e=>((e,t)=>{var n;let r=t;"ArrowRight"===e.key?(r=(t+1)%w.length,e.preventDefault()):"ArrowLeft"===e.key&&(r=(t-1+w.length)%w.length,e.preventDefault()),null===(n=L.current[r])||void 0===n||n.focus()})(e,o),ref:e=>L.current[o]=e,$active:l,children:W(n)})]}),null==i?void 0:i.content]})},o)}))})})};export{p as TabLinkChain};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useContext as n,useRef as r}from"react";import{r as i}from"../external/react-responsive/dist/react-responsive.js";import{ThemeContext as o}from"styled-components";import{Breakpoint as l}from"../theme/index.js";import{TabContext as d}from"./tab-context.js";import{CustomFadeWrapper as a,Chain as c,ChainItem as s,ChainLink as u,LabelContainer as m,Label as f,BoldLabel as h}from"./tab-link-chain.style.js";const p=({controlledMode:p,"data-testid":v,onTabClick:g,fullWidthIndicatorLine:x,fadeColor:$})=>{const{setCurrentActiveIndex:b,currentActiveIndex:k,tabLinks:w,instanceId:C}=n(d),y=n(o),I=l["md-max"]({theme:y}),j=i.useMediaQuery({maxWidth:I}),A=l["lg-max"]({theme:y}),L=r(null),D=r([]),R=r(null),W=e=>t=>{t.preventDefault(),t.stopPropagation(),p||b(e),g&&g(w[e].title,e)},B=e=>j&&e.length>20?`${e.substring(0,20)}...`:e;return e(a,{onResize:({content:e,wrapper:t})=>{e&&t&&window.innerWidth<=A&&L.current&&R.current&&(e.scrollLeft=L.current.getBoundingClientRect().left-R.current.getBoundingClientRect().left)},"data-testid":v,fadeColor:$,children:e(c,{role:"tablist",$fullWidthIndicatorLine:x,ref:R,children:w.map((({title:n,width:r,titleAddon:i},o)=>{const l=k===o;return e(s,{role:"none",$active:l,ref:l?L:null,$width:r,children:t(u,{role:"none",onClick:W(o),"data-testid":`${v}-link-${o}`,$reversed:"left"===(null==i?void 0:i.position),children:[t(m,{role:"none",children:[e(f,{$active:l,onClick:W(o),"aria-hidden":"true",children:B(n)}),e(h,{role:"tab",id:`${C}-tab-${o}`,type:"button","aria-selected":l,tabIndex:l?0:-1,onKeyDown:e=>((e,t)=>{var n;let r=t;"ArrowRight"===e.key?(r=(t+1)%w.length,e.preventDefault()):"ArrowLeft"===e.key&&(r=(t-1+w.length)%w.length,e.preventDefault()),null===(n=D.current[r])||void 0===n||n.focus()})(e,o),ref:e=>D.current[o]=e,$active:l,children:B(n)})]}),null==i?void 0:i.content]})},o)}))})})};export{p as TabLinkChain};
2
2
  //# sourceMappingURL=tab-link-chain.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab-link-chain.js","sources":["../../src/tab/tab-link-chain.tsx"],"sourcesContent":["import { useContext, useRef } from \"react\";\nimport { useMediaQuery } from \"react-responsive\";\nimport { ThemeContext } from \"styled-components\";\nimport { ResizeCallbackParams } from \"../shared/fade-wrapper\";\nimport { Breakpoint } from \"../theme\";\nimport { TabContext } from \"./tab-context\";\nimport {\n BoldLabel,\n Chain,\n ChainItem,\n ChainLink,\n CustomFadeWrapper,\n Label,\n LabelContainer,\n} from \"./tab-link-chain.style\";\nimport { TabProps } from \"./types\";\n\ninterface Props\n extends Pick<\n TabProps,\n \"fullWidthIndicatorLine\" | \"onTabClick\" | \"data-testid\" | \"fadeColor\"\n > {\n controlledMode?: boolean | undefined;\n}\n\nexport const TabLinkChain = ({\n controlledMode,\n \"data-testid\": testId,\n onTabClick,\n fullWidthIndicatorLine,\n fadeColor,\n}: Props) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const { setCurrentActiveIndex, currentActiveIndex, tabLinks } =\n useContext(TabContext);\n\n const theme = useContext(ThemeContext);\n const mobileBreakpoint = Breakpoint[\"md-max\"]({ theme });\n\n const isMobile = useMediaQuery({\n maxWidth: mobileBreakpoint,\n });\n\n const tabletBreakpoint = Breakpoint[\"lg-max\"]({ theme });\n\n const activeLinkRef = useRef<HTMLLIElement>(null);\n const chainLinkRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const chainRef = useRef<HTMLUListElement | null>(null);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChainLinkClick =\n (index: number) =>\n (event: React.MouseEvent<HTMLButtonElement | HTMLDivElement>) => {\n event.preventDefault();\n event.stopPropagation();\n if (!controlledMode) {\n setCurrentActiveIndex(index);\n }\n\n if (onTabClick) {\n onTabClick(tabLinks[index].title, index);\n }\n };\n\n const handleResize = ({ content, wrapper }: ResizeCallbackParams) => {\n if (\n content &&\n wrapper &&\n window.innerWidth <= tabletBreakpoint &&\n activeLinkRef.current &&\n chainRef.current\n ) {\n content.scrollLeft =\n activeLinkRef.current.getBoundingClientRect().left -\n chainRef.current.getBoundingClientRect().left;\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n let nextIndex = index;\n if (e.key === \"ArrowRight\") {\n nextIndex = (index + 1) % tabLinks.length;\n e.preventDefault();\n } else if (e.key === \"ArrowLeft\") {\n nextIndex = (index - 1 + tabLinks.length) % tabLinks.length;\n e.preventDefault();\n }\n\n chainLinkRefs.current[nextIndex]?.focus();\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const truncateText = (value: string) => {\n if (isMobile) {\n return value.length > 20 ? `${value.substring(0, 20)}...` : value;\n }\n\n return value;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n return (\n <CustomFadeWrapper\n onResize={handleResize}\n data-testid={testId}\n fadeColor={fadeColor}\n >\n <Chain\n role=\"tablist\"\n $fullWidthIndicatorLine={fullWidthIndicatorLine}\n ref={chainRef}\n >\n {tabLinks.map(({ title, width, titleAddon }, index) => {\n const isActive = currentActiveIndex === index;\n\n return (\n <ChainItem\n key={index}\n role=\"none\"\n $active={isActive}\n ref={isActive ? activeLinkRef : null}\n $width={width}\n >\n <ChainLink\n role=\"none\"\n onClick={handleChainLinkClick(index)}\n data-testid={`${testId}-link-${index}`}\n $reversed={titleAddon?.position === \"left\"}\n >\n <LabelContainer role=\"none\">\n <Label\n $active={isActive}\n onClick={handleChainLinkClick(index)}\n aria-hidden=\"true\"\n >\n {truncateText(title)}\n </Label>\n <BoldLabel\n role=\"tab\"\n type=\"button\"\n aria-selected={isActive}\n tabIndex={isActive ? 0 : -1}\n onKeyDown={(e) =>\n handleKeyDown(e, index)\n }\n ref={(el) =>\n (chainLinkRefs.current[index] = el)\n }\n $active={isActive}\n >\n {truncateText(title)}\n </BoldLabel>\n </LabelContainer>\n {titleAddon?.content}\n </ChainLink>\n </ChainItem>\n );\n })}\n </Chain>\n </CustomFadeWrapper>\n );\n};\n"],"names":["TabLinkChain","controlledMode","testId","onTabClick","fullWidthIndicatorLine","fadeColor","setCurrentActiveIndex","currentActiveIndex","tabLinks","useContext","TabContext","theme","ThemeContext","mobileBreakpoint","Breakpoint","isMobile","useMediaQuery","maxWidth","tabletBreakpoint","activeLinkRef","useRef","chainLinkRefs","chainRef","handleChainLinkClick","index","event","preventDefault","stopPropagation","title","truncateText","value","length","substring","_jsx","CustomFadeWrapper","onResize","content","wrapper","window","innerWidth","current","scrollLeft","getBoundingClientRect","left","children","Chain","role","$fullWidthIndicatorLine","ref","map","width","titleAddon","isActive","ChainItem","$active","$width","_jsxs","ChainLink","onClick","$reversed","position","LabelContainer","Label","BoldLabel","type","tabIndex","onKeyDown","e","nextIndex","key","_a","focus","handleKeyDown","el"],"mappings":"8cAyBO,MAAMA,EAAe,EACxBC,iBACA,cAAeC,EACfC,aACAC,yBACAC,gBAKA,MAAMC,sBAAEA,EAAqBC,mBAAEA,EAAkBC,SAAEA,GAC/CC,EAAWC,GAETC,EAAQF,EAAWG,GACnBC,EAAmBC,EAAW,UAAU,CAAEH,UAE1CI,EAAWC,EAAAA,cAAc,CAC3BC,SAAUJ,IAGRK,EAAmBJ,EAAW,UAAU,CAAEH,UAE1CQ,EAAgBC,EAAsB,MACtCC,EAAgBD,EAAqC,IACrDE,EAAWF,EAAgC,MAK3CG,EACDC,GACAC,IACGA,EAAMC,iBACND,EAAME,kBACD1B,GACDK,EAAsBkB,GAGtBrB,GACAA,EAAWK,EAASgB,GAAOI,MAAOJ,EACtC,EAiCFK,EAAgBC,GACdf,GACOe,EAAMC,OAAS,GAAK,GAAGD,EAAME,UAAU,EAAG,SAG9CF,EAMX,OACIG,EAACC,GACGC,SA3Ca,EAAGC,UAASC,cAEzBD,GACAC,GACAC,OAAOC,YAAcrB,GACrBC,EAAcqB,SACdlB,EAASkB,UAETJ,EAAQK,WACJtB,EAAcqB,QAAQE,wBAAwBC,KAC9CrB,EAASkB,QAAQE,wBAAwBC,KACjD,EAgC0B,cACTzC,EACbG,UAAWA,EAASuC,SAEpBX,EAACY,EAAK,CACFC,KAAK,UAASC,wBACW3C,EACzB4C,IAAK1B,WAEJd,EAASyC,KAAI,EAAGrB,QAAOsB,QAAOC,cAAc3B,KACzC,MAAM4B,EAAW7C,IAAuBiB,EAExC,OACIS,EAACoB,EAAS,CAENP,KAAK,OAAMQ,QACFF,EACTJ,IAAKI,EAAWjC,EAAgB,KAAIoC,OAC5BL,EAAKN,SAEbY,EAACC,EAAS,CACNX,KAAK,OACLY,QAASnC,EAAqBC,GAAM,cACvB,GAAGtB,UAAesB,IAAOmC,UACF,UAAzBR,aAAU,EAAVA,EAAYS,UAAmBhB,SAAA,CAE1CY,EAACK,EAAc,CAACf,KAAK,iBACjBb,EAAC6B,EAAK,CAAAR,QACOF,EACTM,QAASnC,EAAqBC,GAAM,cACxB,OAAMoB,SAEjBf,EAAaD,KAElBK,EAAC8B,EAAS,CACNjB,KAAK,MACLkB,KAAK,yBACUZ,EACfa,SAAUb,EAAW,KACrBc,UAAYC,GApE1B,EAACA,EAAwB3C,WAC3C,IAAI4C,EAAY5C,EACF,eAAV2C,EAAEE,KACFD,GAAa5C,EAAQ,GAAKhB,EAASuB,OACnCoC,EAAEzC,kBACe,cAAVyC,EAAEE,MACTD,GAAa5C,EAAQ,EAAIhB,EAASuB,QAAUvB,EAASuB,OACrDoC,EAAEzC,kBAG0B,QAAhC4C,EAAAjD,EAAcmB,QAAQ4B,UAAU,IAAAE,GAAAA,EAAEC,OAAO,EA2DLC,CAAcL,EAAG3C,GAErBwB,IAAMyB,GACDpD,EAAcmB,QAAQhB,GAASiD,UAE3BrB,EAAQR,SAEhBf,EAAaD,QAGrBuB,aAAU,EAAVA,EAAYf,YApCZZ,EAsCG,OAIR"}
1
+ {"version":3,"file":"tab-link-chain.js","sources":["../../src/tab/tab-link-chain.tsx"],"sourcesContent":["import { useContext, useRef } from \"react\";\nimport { useMediaQuery } from \"react-responsive\";\nimport { ThemeContext } from \"styled-components\";\nimport { ResizeCallbackParams } from \"../shared/fade-wrapper\";\nimport { Breakpoint } from \"../theme\";\nimport { TabContext } from \"./tab-context\";\nimport {\n BoldLabel,\n Chain,\n ChainItem,\n ChainLink,\n CustomFadeWrapper,\n Label,\n LabelContainer,\n} from \"./tab-link-chain.style\";\nimport { TabProps } from \"./types\";\n\ninterface Props\n extends Pick<\n TabProps,\n \"fullWidthIndicatorLine\" | \"onTabClick\" | \"data-testid\" | \"fadeColor\"\n > {\n controlledMode?: boolean | undefined;\n}\n\nexport const TabLinkChain = ({\n controlledMode,\n \"data-testid\": testId,\n onTabClick,\n fullWidthIndicatorLine,\n fadeColor,\n}: Props) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const { setCurrentActiveIndex, currentActiveIndex, tabLinks, instanceId } =\n useContext(TabContext);\n\n const theme = useContext(ThemeContext);\n const mobileBreakpoint = Breakpoint[\"md-max\"]({ theme });\n\n const isMobile = useMediaQuery({\n maxWidth: mobileBreakpoint,\n });\n\n const tabletBreakpoint = Breakpoint[\"lg-max\"]({ theme });\n\n const activeLinkRef = useRef<HTMLLIElement>(null);\n const chainLinkRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const chainRef = useRef<HTMLUListElement | null>(null);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChainLinkClick =\n (index: number) =>\n (event: React.MouseEvent<HTMLButtonElement | HTMLDivElement>) => {\n event.preventDefault();\n event.stopPropagation();\n if (!controlledMode) {\n setCurrentActiveIndex(index);\n }\n\n if (onTabClick) {\n onTabClick(tabLinks[index].title, index);\n }\n };\n\n const handleResize = ({ content, wrapper }: ResizeCallbackParams) => {\n if (\n content &&\n wrapper &&\n window.innerWidth <= tabletBreakpoint &&\n activeLinkRef.current &&\n chainRef.current\n ) {\n content.scrollLeft =\n activeLinkRef.current.getBoundingClientRect().left -\n chainRef.current.getBoundingClientRect().left;\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n let nextIndex = index;\n if (e.key === \"ArrowRight\") {\n nextIndex = (index + 1) % tabLinks.length;\n e.preventDefault();\n } else if (e.key === \"ArrowLeft\") {\n nextIndex = (index - 1 + tabLinks.length) % tabLinks.length;\n e.preventDefault();\n }\n\n chainLinkRefs.current[nextIndex]?.focus();\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const truncateText = (value: string) => {\n if (isMobile) {\n return value.length > 20 ? `${value.substring(0, 20)}...` : value;\n }\n\n return value;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n return (\n <CustomFadeWrapper\n onResize={handleResize}\n data-testid={testId}\n fadeColor={fadeColor}\n >\n <Chain\n role=\"tablist\"\n $fullWidthIndicatorLine={fullWidthIndicatorLine}\n ref={chainRef}\n >\n {tabLinks.map(({ title, width, titleAddon }, index) => {\n const isActive = currentActiveIndex === index;\n\n return (\n <ChainItem\n key={index}\n role=\"none\"\n $active={isActive}\n ref={isActive ? activeLinkRef : null}\n $width={width}\n >\n <ChainLink\n role=\"none\"\n onClick={handleChainLinkClick(index)}\n data-testid={`${testId}-link-${index}`}\n $reversed={titleAddon?.position === \"left\"}\n >\n <LabelContainer role=\"none\">\n <Label\n $active={isActive}\n onClick={handleChainLinkClick(index)}\n aria-hidden=\"true\"\n >\n {truncateText(title)}\n </Label>\n <BoldLabel\n role=\"tab\"\n id={`${instanceId}-tab-${index}`}\n type=\"button\"\n aria-selected={isActive}\n tabIndex={isActive ? 0 : -1}\n onKeyDown={(e) =>\n handleKeyDown(e, index)\n }\n ref={(el) =>\n (chainLinkRefs.current[index] = el)\n }\n $active={isActive}\n >\n {truncateText(title)}\n </BoldLabel>\n </LabelContainer>\n {titleAddon?.content}\n </ChainLink>\n </ChainItem>\n );\n })}\n </Chain>\n </CustomFadeWrapper>\n );\n};\n"],"names":["TabLinkChain","controlledMode","testId","onTabClick","fullWidthIndicatorLine","fadeColor","setCurrentActiveIndex","currentActiveIndex","tabLinks","instanceId","useContext","TabContext","theme","ThemeContext","mobileBreakpoint","Breakpoint","isMobile","useMediaQuery","maxWidth","tabletBreakpoint","activeLinkRef","useRef","chainLinkRefs","chainRef","handleChainLinkClick","index","event","preventDefault","stopPropagation","title","truncateText","value","length","substring","_jsx","CustomFadeWrapper","onResize","content","wrapper","window","innerWidth","current","scrollLeft","getBoundingClientRect","left","children","Chain","role","$fullWidthIndicatorLine","ref","map","width","titleAddon","isActive","ChainItem","$active","_jsxs","ChainLink","onClick","position","LabelContainer","Label","BoldLabel","id","type","tabIndex","onKeyDown","e","nextIndex","key","_a","focus","handleKeyDown","el"],"mappings":"8cAyBO,MAAMA,EAAe,EACxBC,iBACA,cAAeC,EACfC,aACAC,yBACAC,gBAKA,MAAMC,sBAAEA,EAAqBC,mBAAEA,EAAkBC,SAAEA,EAAQC,WAAEA,GACzDC,EAAWC,GAETC,EAAQF,EAAWG,GACnBC,EAAmBC,EAAW,UAAU,CAAEH,UAE1CI,EAAWC,EAAAA,cAAc,CAC3BC,SAAUJ,IAGRK,EAAmBJ,EAAW,UAAU,CAAEH,UAE1CQ,EAAgBC,EAAsB,MACtCC,EAAgBD,EAAqC,IACrDE,EAAWF,EAAgC,MAK3CG,EACDC,GACAC,IACGA,EAAMC,iBACND,EAAME,kBACD3B,GACDK,EAAsBmB,GAGtBtB,GACAA,EAAWK,EAASiB,GAAOI,MAAOJ,EACtC,EAiCFK,EAAgBC,GACdf,GACOe,EAAMC,OAAS,GAAK,GAAGD,EAAME,UAAU,EAAG,SAG9CF,EAMX,OACIG,EAACC,GACGC,SA3Ca,EAAGC,UAASC,cAEzBD,GACAC,GACAC,OAAOC,YAAcrB,GACrBC,EAAcqB,SACdlB,EAASkB,UAETJ,EAAQK,WACJtB,EAAcqB,QAAQE,wBAAwBC,KAC9CrB,EAASkB,QAAQE,wBAAwBC,KACjD,EAgC0B,cACT1C,EACbG,UAAWA,EAASwC,SAEpBX,EAACY,EAAK,CACFC,KAAK,UAASC,wBACW5C,EACzB6C,IAAK1B,WAEJf,EAAS0C,KAAI,EAAGrB,QAAOsB,QAAOC,cAAc3B,KACzC,MAAM4B,EAAW9C,IAAuBkB,EAExC,OACIS,EAACoB,EAAS,CAENP,KAAK,OAAMQ,QACFF,EACTJ,IAAKI,EAAWjC,EAAgB,YACxB+B,EAAKN,SAEbW,EAACC,EAAS,CACNV,KAAK,OACLW,QAASlC,EAAqBC,GAAM,cACvB,GAAGvB,UAAeuB,cACK,UAAzB2B,eAAAA,EAAYO,UAAmBd,SAAA,CAE1CW,EAACI,EAAc,CAACb,KAAK,OAAMF,SAAA,CACvBX,EAAC2B,WACYR,EACTK,QAASlC,EAAqBC,GAAM,cACxB,gBAEXK,EAAaD,KAElBK,EAAC4B,EAAS,CACNf,KAAK,MACLgB,GAAI,GAAGtD,SAAkBgB,IACzBuC,KAAK,SAAQ,gBACEX,EACfY,SAAUZ,EAAW,GAAI,EACzBa,UAAYC,GArE1B,EAACA,EAAwB1C,WAC3C,IAAI2C,EAAY3C,EACF,eAAV0C,EAAEE,KACFD,GAAa3C,EAAQ,GAAKjB,EAASwB,OACnCmC,EAAExC,kBACe,cAAVwC,EAAEE,MACTD,GAAa3C,EAAQ,EAAIjB,EAASwB,QAAUxB,EAASwB,OACrDmC,EAAExC,kBAG0B,QAAhC2C,EAAAhD,EAAcmB,QAAQ2B,UAAU,IAAAE,GAAAA,EAAEC,OAAO,EA4DLC,CAAcL,EAAG1C,GAErBwB,IAAMwB,GACDnD,EAAcmB,QAAQhB,GAASgD,EAAGlB,QAE9BF,EAAQR,SAEhBf,EAAaD,QAGrBuB,aAAU,EAAVA,EAAYf,YArCZZ,EAuCG,OAIR"}
@@ -0,0 +1,5 @@
1
+ import type { TabListItemProps } from "./types";
2
+ export declare const TabListItem: {
3
+ (_props: TabListItemProps): null;
4
+ displayName: string;
5
+ };
@@ -0,0 +1,2 @@
1
+ const a=a=>null;a.displayName="Tab.TabListItem";export{a as TabListItem};
2
+ //# sourceMappingURL=tab-list-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-list-item.js","sources":["../../src/tab/tab-list-item.tsx"],"sourcesContent":["import type { TabListItemProps } from \"./types\";\n\n// Declarative slot component — props are consumed by Tab.TabList, not rendered\nexport const TabListItem = (_props: TabListItemProps) => null;\n\nTabListItem.displayName = \"Tab.TabListItem\";\n"],"names":["TabListItem","_props","displayName"],"mappings":"AAGO,MAAMA,EAAeC,GAA6B,KAEzDD,EAAYE,YAAc"}
@@ -0,0 +1,5 @@
1
+ import type { TabListProps } from "./types";
2
+ export declare const TabList: {
3
+ ({ children, fullWidthIndicatorLine, fadeColor, "data-testid": testId, }: TabListProps): import("react/jsx-runtime").JSX.Element;
4
+ displayName: string;
5
+ };
@@ -0,0 +1,2 @@
1
+ import{jsx as t}from"react/jsx-runtime";import{useContext as e,useMemo as i,Children as o,useEffect as r}from"react";import"../util/calendar-helper.js";import"../util/date-helper.js";import"../util/date-input-helper.js";import"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{useIsomorphicLayoutEffect as a}from"../util/use-isomorphic-layout-effect.js";import{TabContext as l}from"./tab-context.js";import{TabLinkChain as n}from"./tab-link-chain.js";const d=({children:d,fullWidthIndicatorLine:s,fadeColor:p,"data-testid":m})=>{const{setTabLinks:c,controlledMode:u,onTabClick:f,isContextProvided:b}=e(l),h=i((()=>o.toArray(d).filter(Boolean).map((({props:t})=>({title:t.title,width:t.width,titleAddon:t.titleAddon})))),[d]);return a((()=>{c(h)}),[c,h]),r((()=>{"production"===process.env.NODE_ENV||b||console.error("Tab.TabList must be rendered inside Tab.Context.")}),[b]),t(n,{controlledMode:u,onTabClick:f,"data-testid":m,fullWidthIndicatorLine:s,fadeColor:p})};d.displayName="Tab.TabList";export{d as TabList};
2
+ //# sourceMappingURL=tab-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-list.js","sources":["../../src/tab/tab-list.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\nimport { Children, useContext, useEffect, useMemo } from \"react\";\n\nimport { useIsomorphicLayoutEffect } from \"../util\";\nimport type { TabLinkProps } from \"./tab-context\";\nimport { TabContext } from \"./tab-context\";\nimport { TabLinkChain } from \"./tab-link-chain\";\nimport type { TabListItemProps, TabListProps } from \"./types\";\n\nexport const TabList = ({\n children,\n fullWidthIndicatorLine,\n fadeColor,\n \"data-testid\": testId,\n}: TabListProps) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const { setTabLinks, controlledMode, onTabClick, isContextProvided } =\n useContext(TabContext);\n\n const tabLinks = useMemo(() => {\n return (\n Children.toArray(children).filter(\n Boolean\n ) as ReactElement<TabListItemProps>[]\n ).map(({ props }) => ({\n title: props.title,\n width: props.width,\n titleAddon: props.titleAddon,\n })) as TabLinkProps[];\n }, [children]);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useIsomorphicLayoutEffect(() => {\n setTabLinks(tabLinks);\n }, [setTabLinks, tabLinks]);\n\n useEffect(() => {\n if (process.env.NODE_ENV !== \"production\" && !isContextProvided) {\n console.error(\"Tab.TabList must be rendered inside Tab.Context.\");\n }\n }, [isContextProvided]);\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n return (\n <TabLinkChain\n controlledMode={controlledMode}\n onTabClick={onTabClick}\n data-testid={testId}\n fullWidthIndicatorLine={fullWidthIndicatorLine}\n fadeColor={fadeColor}\n />\n );\n};\n\nTabList.displayName = \"Tab.TabList\";\n"],"names":["TabList","children","fullWidthIndicatorLine","fadeColor","testId","setTabLinks","controlledMode","onTabClick","isContextProvided","useContext","TabContext","tabLinks","useMemo","Children","toArray","filter","Boolean","map","props","title","width","titleAddon","useIsomorphicLayoutEffect","useEffect","process","env","NODE_ENV","console","error","_jsx","TabLinkChain","displayName"],"mappings":"4fASO,MAAMA,EAAU,EACnBC,WACAC,yBACAC,YACA,cAAeC,MAKf,MAAMC,YAAEA,EAAWC,eAAEA,EAAcC,WAAEA,EAAUC,kBAAEA,GAC7CC,EAAWC,GAETC,EAAWC,GAAQ,IAEjBC,EAASC,QAAQb,GAAUc,OACvBC,SAENC,KAAI,EAAGC,YAAO,CACZC,MAAOD,EAAMC,MACbC,MAAOF,EAAME,MACbC,WAAYH,EAAMG,gBAEvB,CAACpB,IAkBJ,OAbAqB,GAA0B,KACtBjB,EAAYM,EAAS,GACtB,CAACN,EAAaM,IAEjBY,GAAU,KACuB,eAAzBC,QAAQC,IAAIC,UAA8BlB,GAC1CmB,QAAQC,MAAM,mDAClB,GACD,CAACpB,IAMAqB,EAACC,EAAY,CACTxB,eAAgBA,EAChBC,WAAYA,gBACCH,EACbF,uBAAwBA,EACxBC,UAAWA,GACb,EAIVH,EAAQ+B,YAAc"}
@@ -0,0 +1,5 @@
1
+ import type { TabPanelProps } from "./types";
2
+ export declare const TabPanel: {
3
+ ({ index, children, ...otherProps }: TabPanelProps): import("react/jsx-runtime").JSX.Element | null;
4
+ displayName: string;
5
+ };
@@ -0,0 +1,2 @@
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsx as r}from"react/jsx-runtime";import{useContext as t,useEffect as n}from"react";import{TabContext as i}from"./tab-context.js";const o=o=>{var{index:a,children:d}=o,l=e(o,["index","children"]);const{currentActiveIndex:s,isContextProvided:c,instanceId:b}=t(i);return n((()=>{"production"===process.env.NODE_ENV||c||console.error("Tab.Panel must be rendered inside Tab.Context.")}),[c]),s===a?r("div",Object.assign({role:"tabpanel","aria-labelledby":`${b}-tab-${a}`,tabIndex:0},l,{children:d})):null};o.displayName="Tab.Panel";export{o as TabPanel};
2
+ //# sourceMappingURL=tab-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-panel.js","sources":["../../src/tab/tab-panel.tsx"],"sourcesContent":["import { useContext, useEffect } from \"react\";\n\nimport { TabContext } from \"./tab-context\";\nimport type { TabPanelProps } from \"./types\";\n\nexport const TabPanel = ({ index, children, ...otherProps }: TabPanelProps) => {\n const { currentActiveIndex, isContextProvided, instanceId } =\n useContext(TabContext);\n\n useEffect(() => {\n if (process.env.NODE_ENV !== \"production\" && !isContextProvided) {\n console.error(\"Tab.Panel must be rendered inside Tab.Context.\");\n }\n }, [isContextProvided]);\n\n return currentActiveIndex === index ? (\n <div\n role=\"tabpanel\"\n aria-labelledby={`${instanceId}-tab-${index}`}\n tabIndex={0}\n {...otherProps}\n >\n {children}\n </div>\n ) : null;\n};\n\nTabPanel.displayName = \"Tab.Panel\";\n"],"names":["TabPanel","_a","index","children","otherProps","__rest","currentActiveIndex","isContextProvided","instanceId","useContext","TabContext","useEffect","process","env","NODE_ENV","console","error","_jsx","Object","assign","role","tabIndex","displayName"],"mappings":"uLAKO,MAAMA,EAAYC,QAAAC,MAAEA,EAAKC,SAAEA,GAAQF,EAAKG,EAAUC,EAAAJ,EAAhC,sBACrB,MAAMK,mBAAEA,EAAkBC,kBAAEA,EAAiBC,WAAEA,GAC3CC,EAAWC,GAQf,OANAC,GAAU,KACuB,eAAzBC,QAAQC,IAAIC,UAA8BP,GAC1CQ,QAAQC,MAAM,iDAClB,GACD,CAACT,IAEGD,IAAuBJ,EAC1Be,EAAA,MAAAC,OAAAC,OAAA,CACIC,KAAK,WAAU,kBACE,GAAGZ,SAAkBN,IACtCmB,SAAU,GACNjB,EAAU,CAAAD,SAEbA,KAEL,IAAI,EAGZH,EAASsB,YAAc"}
package/tab/tab.d.ts CHANGED
@@ -1,10 +1,41 @@
1
1
  import { TabProps } from "./types";
2
+ /**
3
+ * A tabbed-panel layout that switches visible content by selecting a tab link.
4
+ *
5
+ * Use `Tab` to organise content into labelled panels where only one panel is
6
+ * visible at a time. Compose with `Tab.Item` to define each panel.
7
+ *
8
+ * For cases where the tab bar and panels need to be positioned independently,
9
+ * use the standalone composition: `Tab.Context`, `Tab.TabList`,
10
+ * `Tab.TabListItem`, and `Tab.Panel`.
11
+ */
2
12
  export declare const Tab: {
3
13
  ({ children, currentActive: currentActiveIndex, initialActive, onTabClick, "data-testid": testId, fullWidthIndicatorLine, fadeColor, ...otherProps }: TabProps): import("react/jsx-runtime").JSX.Element;
4
14
  displayName: string;
5
15
  } & {
16
+ /** Renders an individual content panel within a `Tab`. Inactive items are unmounted — inner state is not preserved across tab switches. */
6
17
  Item: {
7
18
  ({ index, children, titleAddon: _titleAddon, ...otherProps }: import("./tab-item").TabItemComponentProps): import("react/jsx-runtime").JSX.Element | null;
8
19
  displayName: string;
9
20
  };
21
+ /** Context provider for the standalone TabList + Panel composition. */
22
+ Context: {
23
+ ({ children, currentActive: currentActiveIndex, initialActive, onTabClick, }: import("./types").TabContextProps): import("react/jsx-runtime").JSX.Element;
24
+ displayName: string;
25
+ };
26
+ /** Renders the tab link bar within a `Tab.Context`. */
27
+ TabList: {
28
+ ({ children, fullWidthIndicatorLine, fadeColor, "data-testid": testId, }: import("./types").TabListProps): import("react/jsx-runtime").JSX.Element;
29
+ displayName: string;
30
+ };
31
+ /** Declares a tab entry inside a `Tab.TabList`. */
32
+ TabListItem: {
33
+ (_props: import("./types").TabListItemProps): null;
34
+ displayName: string;
35
+ };
36
+ /** Renders a content panel within a `Tab.Context`. Inactive panels are unmounted — inner state is not preserved across tab switches. */
37
+ Panel: {
38
+ ({ index, children, ...otherProps }: import("./types").TabPanelProps): import("react/jsx-runtime").JSX.Element | null;
39
+ displayName: string;
40
+ };
10
41
  };
package/tab/tab.js CHANGED
@@ -1,2 +1,2 @@
1
- import{__rest as t}from"../_virtual/_tslib.js";import{jsx as i,jsxs as e}from"react/jsx-runtime";import{useState as r,useMemo as o,Children as a,useEffect as n,cloneElement as d}from"react";import{TabContext as l}from"./tab-context.js";import{TabItem as c}from"./tab-item.js";import{TabLinkChain as s}from"./tab-link-chain.js";import{Wrapper as m}from"./tab.style.js";const p=c=>{var{children:p,currentActive:f,initialActive:b=0,onTabClick:u,"data-testid":h,fullWidthIndicatorLine:v,fadeColor:A}=c,j=t(c,["children","currentActive","initialActive","onTabClick","data-testid","fullWidthIndicatorLine","fadeColor"]);const[y,C]=r(f||b),k=o((()=>a.toArray(p).filter(Boolean).map((t=>({title:t.props.title,width:t.props.width,titleAddon:t.props.titleAddon})))),[p]);n((()=>{"number"==typeof f&&C(f)}),[f]);return i(m,Object.assign({"data-testid":h},j,{children:e(l.Provider,{value:{tabLinks:k,currentActiveIndex:y,setCurrentActiveIndex:C},children:[i(s,{controlledMode:"number"==typeof f,onTabClick:u,"data-testid":`${h}-tabs`,fullWidthIndicatorLine:v,fadeColor:A}),a.toArray(p).filter(Boolean).map(((t,i)=>d(t,{key:i,index:i})))]})}))};p.displayName="Tab";const f=Object.assign(p,{Item:c});export{f as Tab};
1
+ import{__rest as t}from"../_virtual/_tslib.js";import{jsx as i,jsxs as e}from"react/jsx-runtime";import{useState as r,useMemo as o,Children as a,useEffect as n,cloneElement as l}from"react";import"../util/calendar-helper.js";import"../util/date-helper.js";import"../util/date-input-helper.js";import{useId as s}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{noop as d,TabContext as m}from"./tab-context.js";import{TabContextProvider as p}from"./tab-context-provider.js";import{TabItem as c}from"./tab-item.js";import{TabLinkChain as b}from"./tab-link-chain.js";import{TabList as f}from"./tab-list.js";import{TabListItem as u}from"./tab-list-item.js";import{TabPanel as j}from"./tab-panel.js";import{Wrapper as h}from"./tab.style.js";const v=p=>{var{children:c,currentActive:f,initialActive:u=0,onTabClick:j,"data-testid":v,fullWidthIndicatorLine:A,fadeColor:C}=p,x=t(p,["children","currentActive","initialActive","onTabClick","data-testid","fullWidthIndicatorLine","fadeColor"]);const[k,y]=r(f||u),I=s(),T=o((()=>a.toArray(c).filter(Boolean).map((t=>({title:t.props.title,width:t.props.width,titleAddon:t.props.titleAddon})))),[c]),L=o((()=>({instanceId:I,tabLinks:T,currentActiveIndex:k,setCurrentActiveIndex:y,setTabLinks:d,controlledMode:"number"==typeof f,onTabClick:j,isContextProvided:!0})),[k,f,I,j,T]);n((()=>{"number"==typeof f&&y(f)}),[f]);return i(h,Object.assign({"data-testid":v},x,{children:e(m.Provider,{value:L,children:[i(b,{controlledMode:"number"==typeof f,onTabClick:j,"data-testid":`${v}-tabs`,fullWidthIndicatorLine:A,fadeColor:C}),a.toArray(c).filter(Boolean).map(((t,i)=>l(t,{key:i,index:i})))]})}))};v.displayName="Tab";const A=Object.assign(v,{Item:c,Context:p,TabList:f,TabListItem:u,Panel:j});export{A as Tab};
2
2
  //# sourceMappingURL=tab.js.map
package/tab/tab.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tab.js","sources":["../../src/tab/tab.tsx"],"sourcesContent":["import {\n Children,\n ReactElement,\n cloneElement,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { TabContext, TabLinkProps } from \"./tab-context\";\nimport { TabItem } from \"./tab-item\";\nimport { TabLinkChain } from \"./tab-link-chain\";\nimport { Wrapper } from \"./tab.style\";\nimport { TabItemProps, TabProps } from \"./types\";\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\nconst TabBase = ({\n children,\n currentActive: currentActiveIndex,\n initialActive = 0,\n onTabClick,\n \"data-testid\": testId,\n fullWidthIndicatorLine,\n fadeColor,\n ...otherProps\n}: TabProps) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const [currentActive, setCurrentActive] = useState<number>(\n currentActiveIndex || initialActive\n );\n\n const tabLinks = useMemo(() => {\n const validChildren = Children.toArray(children).filter(\n Boolean\n ) as ReactElement<TabItemProps>[];\n\n return validChildren.map((child) => {\n return {\n title: child.props.title,\n width: child.props.width,\n titleAddon: child.props.titleAddon,\n };\n }) as TabLinkProps[];\n }, [children]);\n\n // =========================================================================\n // Effects\n // =========================================================================\n useEffect(() => {\n if (typeof currentActiveIndex === \"number\") {\n setCurrentActive(currentActiveIndex);\n }\n }, [currentActiveIndex]);\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderChildren = () => {\n const validChildren = Children.toArray(children).filter(Boolean);\n\n return validChildren.map((child, index) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return cloneElement(child as ReactElement<any>, {\n key: index,\n index,\n });\n });\n };\n\n return (\n <Wrapper data-testid={testId} {...otherProps}>\n <TabContext.Provider\n value={{\n tabLinks,\n currentActiveIndex: currentActive,\n setCurrentActiveIndex: setCurrentActive,\n }}\n >\n <TabLinkChain\n controlledMode={typeof currentActiveIndex === \"number\"}\n onTabClick={onTabClick}\n data-testid={`${testId}-tabs`}\n fullWidthIndicatorLine={fullWidthIndicatorLine}\n fadeColor={fadeColor}\n />\n {renderChildren()}\n </TabContext.Provider>\n </Wrapper>\n );\n};\n\nTabBase.displayName = \"Tab\";\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\nexport const Tab = Object.assign(TabBase, {\n Item: TabItem,\n});\n"],"names":["TabBase","_a","children","currentActive","currentActiveIndex","initialActive","onTabClick","testId","fullWidthIndicatorLine","fadeColor","otherProps","__rest","setCurrentActive","useState","tabLinks","useMemo","Children","toArray","filter","Boolean","map","child","title","props","width","titleAddon","useEffect","_jsx","Wrapper","Object","assign","_jsxs","TabContext","Provider","value","setCurrentActiveIndex","TabLinkChain","controlledMode","index","cloneElement","key","displayName","Tab","Item","TabItem"],"mappings":"gXAiBA,MAAMA,EAAWC,QAAAC,SACbA,EACAC,cAAeC,EAAkBC,cACjCA,EAAgB,EAACC,WACjBA,EACA,cAAeC,EAAMC,uBACrBA,EAAsBC,UACtBA,KACGC,EAAUC,EAAAV,EARA,CAAA,WAAA,gBAAA,gBAAA,aAAA,cAAA,yBAAA,cAab,MAAOE,EAAeS,GAAoBC,EACtCT,GAAsBC,GAGpBS,EAAWC,GAAQ,IACCC,EAASC,QAAQf,GAAUgB,OAC7CC,SAGiBC,KAAKC,IACf,CACHC,MAAOD,EAAME,MAAMD,MACnBE,MAAOH,EAAME,MAAMC,MACnBC,WAAYJ,EAAME,MAAME,gBAGjC,CAACvB,IAKJwB,GAAU,KAC4B,iBAAvBtB,GACPQ,EAAiBR,EACrB,GACD,CAACA,IAiBJ,OACIuB,EAACC,EAAOC,OAAAC,OAAA,CAAA,cAAcvB,GAAYG,EAAU,CAAAR,SACxC6B,EAACC,EAAWC,SAAQ,CAChBC,MAAO,CACHpB,WACAV,mBAAoBD,EACpBgC,sBAAuBvB,GAC1BV,SAAA,CAEDyB,EAACS,EAAY,CACTC,eAA8C,iBAAvBjC,EACvBE,WAAYA,gBACC,GAAGC,SAChBC,uBAAwBA,EACxBC,UAAWA,IAzBDO,EAASC,QAAQf,GAAUgB,OAAOC,SAEnCC,KAAI,CAACC,EAAOiB,IAEtBC,EAAalB,EAA4B,CAC5CmB,IAAKF,EACLA,iBAuBE,EAIlBtC,EAAQyC,YAAc,YAKTC,EAAMb,OAAOC,OAAO9B,EAAS,CACtC2C,KAAMC"}
1
+ {"version":3,"file":"tab.js","sources":["../../src/tab/tab.tsx"],"sourcesContent":["import {\n Children,\n ReactElement,\n cloneElement,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { useId } from \"../util\";\nimport { TabContext, TabLinkProps, noop } from \"./tab-context\";\nimport { TabContextProvider } from \"./tab-context-provider\";\nimport { TabItem } from \"./tab-item\";\nimport { TabLinkChain } from \"./tab-link-chain\";\nimport { TabList } from \"./tab-list\";\nimport { TabListItem } from \"./tab-list-item\";\nimport { TabPanel } from \"./tab-panel\";\nimport { Wrapper } from \"./tab.style\";\nimport { TabItemProps, TabProps } from \"./types\";\n\nconst TabBase = ({\n children,\n currentActive: currentActiveIndex,\n initialActive = 0,\n onTabClick,\n \"data-testid\": testId,\n fullWidthIndicatorLine,\n fadeColor,\n ...otherProps\n}: TabProps) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const [currentActive, setCurrentActive] = useState<number>(\n currentActiveIndex || initialActive\n );\n\n const instanceId = useId();\n\n const tabLinks = useMemo(() => {\n const validChildren = Children.toArray(children).filter(\n Boolean\n ) as ReactElement<TabItemProps>[];\n\n return validChildren.map((child) => {\n return {\n title: child.props.title,\n width: child.props.width,\n titleAddon: child.props.titleAddon,\n };\n }) as TabLinkProps[];\n }, [children]);\n\n const tabContextValue = useMemo(\n () => ({\n instanceId,\n tabLinks,\n currentActiveIndex: currentActive,\n setCurrentActiveIndex: setCurrentActive,\n setTabLinks: noop,\n controlledMode: typeof currentActiveIndex === \"number\",\n onTabClick,\n isContextProvided: true,\n }),\n [currentActive, currentActiveIndex, instanceId, onTabClick, tabLinks]\n );\n\n // =========================================================================\n // Effects\n // =========================================================================\n useEffect(() => {\n if (typeof currentActiveIndex === \"number\") {\n setCurrentActive(currentActiveIndex);\n }\n }, [currentActiveIndex]);\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderChildren = () => {\n const validChildren = Children.toArray(children).filter(Boolean);\n\n return validChildren.map((child, index) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return cloneElement(child as ReactElement<any>, {\n key: index,\n index,\n });\n });\n };\n\n return (\n <Wrapper data-testid={testId} {...otherProps}>\n <TabContext.Provider value={tabContextValue}>\n <TabLinkChain\n controlledMode={typeof currentActiveIndex === \"number\"}\n onTabClick={onTabClick}\n data-testid={`${testId}-tabs`}\n fullWidthIndicatorLine={fullWidthIndicatorLine}\n fadeColor={fadeColor}\n />\n {renderChildren()}\n </TabContext.Provider>\n </Wrapper>\n );\n};\n\nTabBase.displayName = \"Tab\";\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n/**\n * A tabbed-panel layout that switches visible content by selecting a tab link.\n *\n * Use `Tab` to organise content into labelled panels where only one panel is\n * visible at a time. Compose with `Tab.Item` to define each panel.\n *\n * For cases where the tab bar and panels need to be positioned independently,\n * use the standalone composition: `Tab.Context`, `Tab.TabList`,\n * `Tab.TabListItem`, and `Tab.Panel`.\n */\nexport const Tab = Object.assign(TabBase, {\n /** Renders an individual content panel within a `Tab`. Inactive items are unmounted — inner state is not preserved across tab switches. */\n Item: TabItem,\n /** Context provider for the standalone TabList + Panel composition. */\n Context: TabContextProvider,\n /** Renders the tab link bar within a `Tab.Context`. */\n TabList,\n /** Declares a tab entry inside a `Tab.TabList`. */\n TabListItem,\n /** Renders a content panel within a `Tab.Context`. Inactive panels are unmounted — inner state is not preserved across tab switches. */\n Panel: TabPanel,\n});\n"],"names":["TabBase","_a","children","currentActive","currentActiveIndex","initialActive","onTabClick","testId","fullWidthIndicatorLine","fadeColor","otherProps","__rest","setCurrentActive","useState","instanceId","useId","tabLinks","useMemo","Children","toArray","filter","Boolean","map","child","title","props","width","titleAddon","tabContextValue","setCurrentActiveIndex","setTabLinks","noop","controlledMode","isContextProvided","useEffect","_jsx","Wrapper","Object","assign","_jsxs","TabContext","Provider","value","TabLinkChain","index","cloneElement","key","displayName","Tab","Item","TabItem","Context","TabContextProvider","TabList","TabListItem","Panel","TabPanel"],"mappings":"8xBAmBA,MAAMA,EAAWC,QAAAC,SACbA,EACAC,cAAeC,EAAkBC,cACjCA,EAAgB,EAACC,WACjBA,EACA,cAAeC,EAAMC,uBACrBA,EAAsBC,UACtBA,KACGC,EAAUC,EAAAV,EARA,CAAA,WAAA,gBAAA,gBAAA,aAAA,cAAA,yBAAA,cAab,MAAOE,EAAeS,GAAoBC,EACtCT,GAAsBC,GAGpBS,EAAaC,IAEbC,EAAWC,GAAQ,IACCC,EAASC,QAAQjB,GAAUkB,OAC7CC,SAGiBC,KAAKC,IACf,CACHC,MAAOD,EAAME,MAAMD,MACnBE,MAAOH,EAAME,MAAMC,MACnBC,WAAYJ,EAAME,MAAME,gBAGjC,CAACzB,IAEE0B,EAAkBX,GACpB,KAAA,CACIH,aACAE,WACAZ,mBAAoBD,EACpB0B,sBAAuBjB,EACvBkB,YAAaC,EACbC,eAA8C,iBAAvB5B,EACvBE,aACA2B,mBAAmB,KAEvB,CAAC9B,EAAeC,EAAoBU,EAAYR,EAAYU,IAMhEkB,GAAU,KAC4B,iBAAvB9B,GACPQ,EAAiBR,EACrB,GACD,CAACA,IAiBJ,OACI+B,EAACC,EAAOC,OAAAC,OAAA,CAAA,cAAc/B,GAAYG,EAAU,CAAAR,SACxCqC,EAACC,EAAWC,SAAQ,CAACC,MAAOd,EAAe1B,SAAA,CACvCiC,EAACQ,EAAY,CACTX,eAA8C,iBAAvB5B,EACvBE,WAAYA,gBACC,GAAGC,SAChBC,uBAAwBA,EACxBC,UAAWA,IAnBDS,EAASC,QAAQjB,GAAUkB,OAAOC,SAEnCC,KAAI,CAACC,EAAOqB,IAEtBC,EAAatB,EAA4B,CAC5CuB,IAAKF,EACLA,iBAiBE,EAIlB5C,EAAQ+C,YAAc,YAeTC,EAAMX,OAAOC,OAAOtC,EAAS,CAEtCiD,KAAMC,EAENC,QAASC,EAETC,UAEAC,cAEAC,MAAOC"}
package/tab/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { FadeColorSet } from "../shared/fade-wrapper";
1
+ import type React from "react";
2
+ import type { FadeColorSet } from "../shared/fade-wrapper";
2
3
  export interface TabProps {
3
4
  children: JSX.Element | JSX.Element[];
4
5
  /** Specify the initial tab index that is to be displayed */
@@ -31,3 +32,84 @@ export interface TitleAddonProps {
31
32
  /** position of the addon content, defaults to "right" */
32
33
  position?: "left" | "right" | undefined;
33
34
  }
35
+ /**
36
+ * Props for the `Tab.Context` component.
37
+ */
38
+ export interface TabContextProps {
39
+ children: React.ReactNode;
40
+ /**
41
+ * Zero-based index of the tab panel displayed on first render.
42
+ *
43
+ * Ignored when `currentActive` is provided.
44
+ *
45
+ * @default 0
46
+ */
47
+ initialActive?: number | undefined;
48
+ /**
49
+ * Zero-based index of the currently active tab panel.
50
+ *
51
+ * When provided, the component operates in controlled mode — the caller is
52
+ * responsible for updating this value in response to `onTabClick` to
53
+ * reflect tab changes.
54
+ */
55
+ currentActive?: number | undefined;
56
+ /**
57
+ * Called when the user clicks a tab link.
58
+ *
59
+ * @param title The `title` of the clicked `Tab.TabListItem`.
60
+ * @param index The zero-based index of the clicked `Tab.TabListItem`.
61
+ */
62
+ onTabClick?: ((title: string, index: number) => void) | undefined;
63
+ }
64
+ /**
65
+ * Props for the `Tab.TabList` component.
66
+ */
67
+ export interface TabListProps {
68
+ children: React.ReactNode;
69
+ "data-testid"?: string | undefined;
70
+ /**
71
+ * Extends all tab indicator lines to the full width
72
+ * of the tab bar instead of matching only the tab link width.
73
+ *
74
+ * @default false
75
+ */
76
+ fullWidthIndicatorLine?: boolean | undefined;
77
+ /**
78
+ * Background color(s) used for the fade overlays at the edges of the
79
+ * scrollable tab link bar.
80
+ *
81
+ * Pass a `string[]` to apply the same gradient stop colors on both edges,
82
+ * or a `FadeColorSet` to specify left and right edges independently.
83
+ */
84
+ fadeColor?: string[] | FadeColorSet | undefined;
85
+ }
86
+ /**
87
+ * Props for the `Tab.TabListItem` component.
88
+ */
89
+ export interface TabListItemProps {
90
+ /**
91
+ * Text label rendered in the tab link bar for this item.
92
+ */
93
+ title: string;
94
+ /**
95
+ * Optional addon element rendered alongside the tab title in the link bar.
96
+ */
97
+ titleAddon?: TitleAddonProps | undefined;
98
+ /**
99
+ * Explicit width for this tab link in the tab bar. Accepts any valid CSS width value.
100
+ */
101
+ width?: string | undefined;
102
+ }
103
+ /**
104
+ * Props for the `Tab.Panel` component.
105
+ */
106
+ export interface TabPanelProps {
107
+ /**
108
+ * Zero-based index identifying which active tab this panel corresponds to.
109
+ */
110
+ index: number;
111
+ children: React.ReactNode;
112
+ className?: string | undefined;
113
+ id?: string | undefined;
114
+ "data-testid"?: string | undefined;
115
+ }