no-frills-ui 0.0.14-alpha.10 → 0.0.14-alpha.12

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 (91) hide show
  1. package/README.md +2 -3
  2. package/dist/index.js +329 -170
  3. package/dist/index.js.map +1 -1
  4. package/lib-esm/components/Accordion/Accordion.js +3 -2
  5. package/lib-esm/components/Accordion/Accordion.js.map +1 -1
  6. package/lib-esm/components/Accordion/AccordionStep.js +13 -9
  7. package/lib-esm/components/Accordion/AccordionStep.js.map +1 -1
  8. package/lib-esm/components/Badge/Badge.js +6 -2
  9. package/lib-esm/components/Badge/Badge.js.map +1 -1
  10. package/lib-esm/components/Button/ActionButton.js +6 -2
  11. package/lib-esm/components/Button/ActionButton.js.map +1 -1
  12. package/lib-esm/components/Button/Button.js +6 -2
  13. package/lib-esm/components/Button/Button.js.map +1 -1
  14. package/lib-esm/components/Button/IconButton.js +6 -2
  15. package/lib-esm/components/Button/IconButton.js.map +1 -1
  16. package/lib-esm/components/Button/LinkButton.js +6 -2
  17. package/lib-esm/components/Button/LinkButton.js.map +1 -1
  18. package/lib-esm/components/Button/RaisedButton.js +6 -2
  19. package/lib-esm/components/Button/RaisedButton.js.map +1 -1
  20. package/lib-esm/components/Card/Card.js +6 -2
  21. package/lib-esm/components/Card/Card.js.map +1 -1
  22. package/lib-esm/components/Chip/Chip.js +7 -3
  23. package/lib-esm/components/Chip/Chip.js.map +1 -1
  24. package/lib-esm/components/ChipInput/ChipInput.d.ts +3 -3
  25. package/lib-esm/components/ChipInput/ChipInput.js +10 -4
  26. package/lib-esm/components/ChipInput/ChipInput.js.map +1 -1
  27. package/lib-esm/components/Dialog/Dialog.d.ts +2 -0
  28. package/lib-esm/components/Dialog/Dialog.js +9 -2
  29. package/lib-esm/components/Dialog/Dialog.js.map +1 -1
  30. package/lib-esm/components/Dialog/PromptDialog.js +5 -3
  31. package/lib-esm/components/Dialog/PromptDialog.js.map +1 -1
  32. package/lib-esm/components/DragAndDrop/DragAndDrop.js +6 -2
  33. package/lib-esm/components/DragAndDrop/DragAndDrop.js.map +1 -1
  34. package/lib-esm/components/Drawer/Drawer.d.ts +6 -2
  35. package/lib-esm/components/Drawer/Drawer.js +32 -24
  36. package/lib-esm/components/Drawer/Drawer.js.map +1 -1
  37. package/lib-esm/components/Groups/Group.d.ts +4 -3
  38. package/lib-esm/components/Groups/Group.js +7 -3
  39. package/lib-esm/components/Groups/Group.js.map +1 -1
  40. package/lib-esm/components/Input/Checkbox.js +8 -4
  41. package/lib-esm/components/Input/Checkbox.js.map +1 -1
  42. package/lib-esm/components/Input/Dropdown.d.ts +5 -6
  43. package/lib-esm/components/Input/Dropdown.js +6 -1
  44. package/lib-esm/components/Input/Dropdown.js.map +1 -1
  45. package/lib-esm/components/Input/Input.d.ts +5 -0
  46. package/lib-esm/components/Input/Input.js +12 -6
  47. package/lib-esm/components/Input/Input.js.map +1 -1
  48. package/lib-esm/components/Input/Radio.js +8 -4
  49. package/lib-esm/components/Input/Radio.js.map +1 -1
  50. package/lib-esm/components/Input/RadioButton.js +8 -4
  51. package/lib-esm/components/Input/RadioButton.js.map +1 -1
  52. package/lib-esm/components/Input/Select.js +13 -7
  53. package/lib-esm/components/Input/Select.js.map +1 -1
  54. package/lib-esm/components/Input/TextArea.js +12 -6
  55. package/lib-esm/components/Input/TextArea.js.map +1 -1
  56. package/lib-esm/components/Input/Toggle.js +7 -3
  57. package/lib-esm/components/Input/Toggle.js.map +1 -1
  58. package/lib-esm/components/Menu/Menu.js +6 -1
  59. package/lib-esm/components/Menu/Menu.js.map +1 -1
  60. package/lib-esm/components/Menu/MenuItem.d.ts +6 -0
  61. package/lib-esm/components/Menu/MenuItem.js +7 -2
  62. package/lib-esm/components/Menu/MenuItem.js.map +1 -1
  63. package/lib-esm/components/Modal/Modal.d.ts +6 -2
  64. package/lib-esm/components/Modal/Modal.js +31 -27
  65. package/lib-esm/components/Modal/Modal.js.map +1 -1
  66. package/lib-esm/components/Notification/Notification.d.ts +2 -0
  67. package/lib-esm/components/Notification/Notification.js +13 -7
  68. package/lib-esm/components/Notification/Notification.js.map +1 -1
  69. package/lib-esm/components/Notification/NotificationManager.js +1 -0
  70. package/lib-esm/components/Notification/NotificationManager.js.map +1 -1
  71. package/lib-esm/components/Notification/index.d.ts +1 -0
  72. package/lib-esm/components/Popover/Popover.js +7 -3
  73. package/lib-esm/components/Popover/Popover.js.map +1 -1
  74. package/lib-esm/components/Spinner/Spinner.js +6 -2
  75. package/lib-esm/components/Spinner/Spinner.js.map +1 -1
  76. package/lib-esm/components/Stepper/Step.js +6 -2
  77. package/lib-esm/components/Stepper/Step.js.map +1 -1
  78. package/lib-esm/components/Stepper/Stepper.js +17 -10
  79. package/lib-esm/components/Stepper/Stepper.js.map +1 -1
  80. package/lib-esm/components/Tabs/Tabs.d.ts +1 -1
  81. package/lib-esm/components/Tabs/Tabs.js +22 -14
  82. package/lib-esm/components/Tabs/Tabs.js.map +1 -1
  83. package/lib-esm/components/Tooltip/Tooltip.js +7 -3
  84. package/lib-esm/components/Tooltip/Tooltip.js.map +1 -1
  85. package/lib-esm/index.js +43 -0
  86. package/lib-esm/shared/LayerManager.d.ts +2 -2
  87. package/lib-esm/shared/LayerManager.js +1 -1
  88. package/lib-esm/shared/LayerManager.js.map +1 -1
  89. package/package.json +28 -18
  90. package/lib-esm/components/index.js +0 -43
  91. /package/lib-esm/{components/index.js.map → index.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.js","sources":["../../../src/components/Input/TextArea.tsx"],"sourcesContent":["import React, { useState, useEffect, useId } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\ntype TextAreaProps = {\n /** Label for the field */\n label: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.InputHTMLAttributes<HTMLTextAreaElement>;\n\ntype TextAreaInternalProps = {\n touched: boolean;\n errorText?: string;\n};\n\nconst Label = styled.label`\n display: inline-flex;\n flex-direction: column;\n position: relative;\n margin: 10px 5px;\n`;\n\nconst TextField = styled.textarea<TextAreaInternalProps>`\n border: none;\n color: inherit;\n padding: 8px;\n min-height: 150px;\n min-width: 250px;\n border-radius: 3px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n display: inline-block;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n\n /** Focused */\n &:focus,\n &:active {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:focus + span,\n &:active + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /** Disabled */\n &:disabled {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BACKGROUND)};\n }\n\n &:disabled + span {\n color: ${getThemeValue(THEME_NAME.DISABLED)};\n }\n\n /** Invalid */\n &:focus:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.ERROR_LIGHT)};\n }\n\n ${(props) =>\n props.touched\n ? `\n &:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n &:invalid + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Error */\n ${(props) =>\n props.errorText\n ? `\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n\n & + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Required */\n &:required + span:after {\n content: '*';\n margin-left: 2px;\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n /** Label Animation */\n & + span {\n position: absolute;\n padding: 0 5px;\n top: 0px;\n left: 4px;\n font-size: 14px;\n line-height: 32px;\n transition: all 300ms ease;\n }\n\n ${(props) =>\n props.value !== ''\n ? `\n & + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n `\n : ''}\n\n &:focus + span, &:placeholder-shown + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n`;\n\nconst ErrorContainer = styled.div`\n color: ${getThemeValue(THEME_NAME.ERROR)};\n padding-top: 3px;\n font-size: 12px;\n line-height: 14px;\n margin-left: 3px;\n`;\n\nfunction TextAreaComponent(props: TextAreaProps, ref: React.Ref<HTMLTextAreaElement>) {\n const { label, errorText, value: propsValue, required, ...rest } = props;\n const [touched, setTouched] = useState(false);\n const [value, setValue] = useState(propsValue || '');\n const errorId = useId();\n\n useEffect(() => {\n if (propsValue !== undefined) {\n setValue(propsValue);\n }\n }, [propsValue]);\n\n const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {\n setTouched(true);\n if (props.onFocus) {\n props.onFocus(e);\n }\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (props.onChange) {\n setValue(e.target.value);\n props.onChange(e);\n } else {\n setValue(e.target.value);\n }\n };\n\n return (\n <Label>\n <TextField\n {...rest}\n ref={ref}\n value={value}\n onChange={onChangeHandler}\n onFocus={handleFocus}\n touched={touched}\n required={required}\n aria-invalid={!!errorText}\n aria-required={required}\n aria-describedby={errorText ? errorId : undefined}\n />\n <span>{label}</span>\n {errorText && <ErrorContainer id={errorId}>{errorText}</ErrorContainer>}\n </Label>\n );\n}\n\nconst TextArea = React.forwardRef(TextAreaComponent);\nexport default TextArea;\n"],"names":["Label","styled","TextField","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","DISABLED_BACKGROUND","DISABLED","ERROR","ERROR_LIGHT","props","touched","errorText","value","ErrorContainer","TextAreaComponent","ref","label","propsValue","required","rest","setTouched","useState","setValue","errorId","useId","useEffect","undefined","handleFocus","e","onFocus","onChangeHandler","onChange","target","_jsxs","_jsx","aria-invalid","aria-required","aria-describedby","span","id","TextArea","React","forwardRef"],"mappings":"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"}
1
+ {"version":3,"file":"TextArea.js","sources":["../../../src/components/Input/TextArea.tsx"],"sourcesContent":["import React, { useState, useEffect, useId, useRef } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\ntype TextAreaProps = {\n /** Label for the field */\n label: string;\n /** Error text to be shown below the field */\n errorText?: string;\n} & React.InputHTMLAttributes<HTMLTextAreaElement>;\n\ntype TextAreaInternalProps = {\n touched: boolean;\n errorText?: string;\n};\n\nconst Label = styled.label`\n display: inline-flex;\n flex-direction: column;\n position: relative;\n margin: 10px 5px;\n`;\n\nconst TextField = styled.textarea<TextAreaInternalProps>`\n border: none;\n color: inherit;\n padding: 8px;\n min-height: 150px;\n min-width: 250px;\n border-radius: 3px;\n border: 1px solid ${getThemeValue(THEME_NAME.BORDER_COLOR)};\n display: inline-block;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n\n /** Focused */\n &:focus,\n &:active {\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:focus + span,\n &:active + span {\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /** Disabled */\n &:disabled {\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n background-color: ${getThemeValue(THEME_NAME.DISABLED_BACKGROUND)};\n }\n\n &:disabled + span {\n color: ${getThemeValue(THEME_NAME.DISABLED)};\n }\n\n /** Invalid */\n &:focus:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.ERROR_LIGHT)};\n }\n\n ${(props) =>\n props.touched\n ? `\n &:invalid {\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n &:invalid + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Error */\n ${(props) =>\n props.errorText\n ? `\n border-color: ${getThemeValue(THEME_NAME.ERROR)};\n\n & + span {\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n `\n : ''}\n\n /** Required */\n &:required + span:after {\n content: '*';\n margin-left: 2px;\n color: ${getThemeValue(THEME_NAME.ERROR)};\n }\n\n /** Label Animation */\n & + span {\n position: absolute;\n padding: 0 5px;\n top: 0px;\n left: 4px;\n font-size: 14px;\n line-height: 32px;\n transition: all 300ms ease;\n }\n\n ${(props) =>\n props.value !== ''\n ? `\n & + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n `\n : ''}\n\n &:focus + span, &:placeholder-shown + span {\n top: -8px;\n background: ${getThemeValue(THEME_NAME.BACKGROUND)};\n font-size: 12px;\n line-height: 14px;\n }\n`;\n\nconst ErrorContainer = styled.div`\n color: ${getThemeValue(THEME_NAME.ERROR)};\n padding-top: 3px;\n font-size: 12px;\n line-height: 14px;\n margin-left: 3px;\n`;\n\n/**\n * TextArea Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLTextAreaElement\n */\nfunction TextAreaComponent(props: TextAreaProps, ref: React.Ref<HTMLTextAreaElement>) {\n const { label, errorText, value: propsValue, required, ...rest } = props;\n const [touched, setTouched] = useState(false);\n const [value, setValue] = useState(propsValue || '');\n const errorId = useId();\n const prevValueRef = useRef<string>(undefined);\n\n useEffect(() => {\n if (propsValue !== undefined && propsValue !== prevValueRef.current) {\n setValue(propsValue);\n prevValueRef.current = propsValue as string;\n }\n }, [propsValue]);\n\n const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {\n setTouched(true);\n if (props.onFocus) {\n props.onFocus(e);\n }\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (props.onChange) {\n setValue(e.target.value);\n props.onChange(e);\n } else {\n setValue(e.target.value);\n }\n };\n\n return (\n <Label>\n <TextField\n {...rest}\n ref={ref}\n value={value}\n onChange={onChangeHandler}\n onFocus={handleFocus}\n touched={touched}\n required={required}\n aria-invalid={!!errorText}\n aria-required={required}\n aria-describedby={errorText ? errorId : undefined}\n />\n <span>{label}</span>\n {errorText && <ErrorContainer id={errorId}>{errorText}</ErrorContainer>}\n </Label>\n );\n}\n\nconst TextArea = React.forwardRef(TextAreaComponent);\nexport default TextArea;\n"],"names":["Label","styled","TextField","getThemeValue","THEME_NAME","BORDER_COLOR","BACKGROUND","PRIMARY","PRIMARY_LIGHT","DISABLED_BORDER","DISABLED_BACKGROUND","DISABLED","ERROR","ERROR_LIGHT","props","touched","errorText","value","ErrorContainer","TextAreaComponent","ref","label","propsValue","required","rest","setTouched","useState","setValue","errorId","useId","prevValueRef","useRef","undefined","useEffect","current","handleFocus","e","onFocus","onChangeHandler","onChange","target","_jsxs","_jsx","aria-invalid","aria-required","aria-describedby","span","id","TextArea","React","forwardRef"],"mappings":"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"}
@@ -4,14 +4,18 @@ import styled from '@emotion/styled';
4
4
  import { getThemeValue, THEME_NAME } from '../../shared/constants.js';
5
5
 
6
6
  const Switch = /*#__PURE__*/ styled("label", {
7
- target: "ebp76g50",
7
+ target: "e185uavx0",
8
8
  label: "Switch"
9
9
  })("position:relative;display:inline-flex;margin:5px 0;");
10
10
  const Input$1 = /*#__PURE__*/ styled("input", {
11
- target: "ebp76g51",
11
+ target: "e185uavx1",
12
12
  label: "Input"
13
13
  })("position:absolute;width:0;height:0;appearance:none;margin:0;& + span{position:relative;cursor:pointer;width:30px;height:18px;background-color:", getThemeValue(THEME_NAME.LIGHT_GREY), ";transition:0.4s;border-radius:10px;padding:0 3px;margin:0 10px 0 5px;}& + span:before{position:absolute;content:'';height:14px;width:14px;left:1px;top:1px;border:1px solid ", getThemeValue(THEME_NAME.DISABLED_BORDER), ";border-radius:50%;background-color:", getThemeValue(THEME_NAME.BACKGROUND), ";transition:0.4s;}&:checked + span{background-color:", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}&:checked + span:before{transform:translateX(18px);border-color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:enabled:focus + span:before{box-shadow:0 0 0 3px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";border-color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:enabled:hover ~ span{cursor:pointer;color:", getThemeValue(THEME_NAME.PRIMARY), ";}&:disabled ~ span{color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";}&:disabled + span{background-color:", getThemeValue(THEME_NAME.LIGHT_GREY), ";cursor:not-allowed;}&:disabled + span:before{background-color:", getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR), ";border-color:", getThemeValue(THEME_NAME.DISABLED_BORDER), ";}");
14
- function ToggleComponent(props, ref) {
14
+ /**
15
+ * Toggle Component
16
+ * @param props - Component props
17
+ * @param ref - Ref forwarded to the underlying HTMLInputElement
18
+ */ function ToggleComponent(props, ref) {
15
19
  return /*#__PURE__*/ jsxs(Switch, {
16
20
  children: [
17
21
  /*#__PURE__*/ jsx(Input$1, {
@@ -1 +1 @@
1
- {"version":3,"file":"Toggle.js","sources":["../../../src/components/Input/Toggle.tsx"],"sourcesContent":["import React from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Switch = styled.label`\n position: relative;\n display: inline-flex;\n margin: 5px 0;\n`;\n\nconst Input = styled.input`\n position: absolute;\n width: 0;\n height: 0;\n appearance: none;\n margin: 0;\n\n & + span {\n position: relative;\n cursor: pointer;\n width: 30px;\n height: 18px;\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n transition: 0.4s;\n border-radius: 10px;\n padding: 0 3px;\n margin: 0 10px 0 5px;\n }\n & + span:before {\n position: absolute;\n content: '';\n height: 14px;\n width: 14px;\n left: 1px;\n top: 1px;\n border: 1px solid ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n border-radius: 50%;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n transition: 0.4s;\n }\n\n /* checked */\n &:checked + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:checked + span:before {\n transform: translateX(18px);\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* focus */\n &:enabled:focus + span:before {\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* hover */\n &:enabled:hover ~ span {\n cursor: pointer;\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* disabled */\n &:disabled ~ span {\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled + span {\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n cursor: not-allowed;\n }\n\n &:disabled + span:before {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n`;\n\ntype ToggleProps = {\n /** Label for the field */\n label?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\nfunction ToggleComponent(props: ToggleProps, ref: React.Ref<HTMLInputElement>) {\n return (\n <Switch>\n <Input\n {...props}\n ref={ref}\n type=\"checkbox\"\n role=\"switch\"\n aria-checked={props.checked}\n />\n <span></span>\n <span>{props.label}</span>\n </Switch>\n );\n}\n\nconst Toggle = React.forwardRef(ToggleComponent);\nexport default Toggle;\n"],"names":["Switch","styled","Input","getThemeValue","THEME_NAME","LIGHT_GREY","DISABLED_BORDER","BACKGROUND","PRIMARY_LIGHT","PRIMARY","BORDER_LIGHT_COLOR","ToggleComponent","props","ref","_jsxs","_jsx","type","role","aria-checked","checked","span","label","Toggle","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,MAAAA,iBAASC,MAAAA,CAAAA,OAAAA,EAAAA;;;;AAMf,MAAMC,OAAAA,iBAAQD,MAAAA,CAAAA,OAAAA,EAAAA;;;qJAYcE,aAAAA,CAAcC,UAAAA,CAAWC,UAAU,CAAA,EAAA,+KAAA,EAanCF,aAAAA,CAAcC,WAAWE,eAAe,CAAA,EAAA,sCAAA,EAExCH,cAAcC,UAAAA,CAAWG,UAAU,2DAMnCJ,aAAAA,CAAcC,UAAAA,CAAWI,aAAa,CAAA,EAAA,oEAAA,EAK1CL,aAAAA,CAAcC,WAAWK,OAAO,CAAA,EAAA,uDAAA,EAKxBN,cAAcC,UAAAA,CAAWI,aAAa,qBAC9CL,aAAAA,CAAcC,UAAAA,CAAWK,OAAO,CAAA,EAAA,gDAAA,EAMvCN,aAAAA,CAAcC,WAAWK,OAAO,CAAA,EAAA,4BAAA,EAKhCN,cAAcC,UAAAA,CAAWE,eAAe,4CAI7BH,aAAAA,CAAcC,UAAAA,CAAWC,UAAU,CAAA,EAAA,iEAAA,EAKnCF,aAAAA,CAAcC,WAAWM,kBAAkB,CAAA,EAAA,gBAAA,EAC/CP,aAAAA,CAAcC,UAAAA,CAAWE,eAAe,CAAA,EAAA,IAAA,CAAA;AAShE,SAASK,eAAAA,CAAgBC,KAAkB,EAAEC,GAAgC,EAAA;AACzE,IAAA,qBACIC,IAAA,CAACd,MAAAA,EAAAA;;0BACGe,GAAA,CAACb,OAAAA,EAAAA;AACI,gBAAA,GAAGU,KAAK;gBACTC,GAAAA,EAAKA,GAAAA;gBACLG,IAAAA,EAAK,UAAA;gBACLC,IAAAA,EAAK,QAAA;AACLC,gBAAAA,cAAAA,EAAcN,MAAMO;;0BAExBJ,GAAA,CAACK,MAAAA,EAAAA,EAAAA,CAAAA;0BACDL,GAAA,CAACK,MAAAA,EAAAA;AAAMR,gBAAAA,QAAAA,EAAAA,KAAAA,CAAMS;;;;AAGzB;AAEA,MAAMC,MAAAA,iBAASC,KAAAA,CAAMC,UAAU,CAACb,eAAAA;;;;"}
1
+ {"version":3,"file":"Toggle.js","sources":["../../../src/components/Input/Toggle.tsx"],"sourcesContent":["import React from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\n\nconst Switch = styled.label`\n position: relative;\n display: inline-flex;\n margin: 5px 0;\n`;\n\nconst Input = styled.input`\n position: absolute;\n width: 0;\n height: 0;\n appearance: none;\n margin: 0;\n\n & + span {\n position: relative;\n cursor: pointer;\n width: 30px;\n height: 18px;\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n transition: 0.4s;\n border-radius: 10px;\n padding: 0 3px;\n margin: 0 10px 0 5px;\n }\n & + span:before {\n position: absolute;\n content: '';\n height: 14px;\n width: 14px;\n left: 1px;\n top: 1px;\n border: 1px solid ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n border-radius: 50%;\n background-color: ${getThemeValue(THEME_NAME.BACKGROUND)};\n transition: 0.4s;\n }\n\n /* checked */\n &:checked + span {\n background-color: ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n\n &:checked + span:before {\n transform: translateX(18px);\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* focus */\n &:enabled:focus + span:before {\n box-shadow: 0 0 0 3px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n border-color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* hover */\n &:enabled:hover ~ span {\n cursor: pointer;\n color: ${getThemeValue(THEME_NAME.PRIMARY)};\n }\n\n /* disabled */\n &:disabled ~ span {\n color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n\n &:disabled + span {\n background-color: ${getThemeValue(THEME_NAME.LIGHT_GREY)};\n cursor: not-allowed;\n }\n\n &:disabled + span:before {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n border-color: ${getThemeValue(THEME_NAME.DISABLED_BORDER)};\n }\n`;\n\ntype ToggleProps = {\n /** Label for the field */\n label?: string;\n} & React.InputHTMLAttributes<HTMLInputElement>;\n\n/**\n * Toggle Component\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLInputElement\n */\nfunction ToggleComponent(props: ToggleProps, ref: React.Ref<HTMLInputElement>) {\n return (\n <Switch>\n <Input\n {...props}\n ref={ref}\n type=\"checkbox\"\n role=\"switch\"\n aria-checked={props.checked}\n />\n <span></span>\n <span>{props.label}</span>\n </Switch>\n );\n}\n\nconst Toggle = React.forwardRef(ToggleComponent);\nexport default Toggle;\n"],"names":["Switch","styled","Input","getThemeValue","THEME_NAME","LIGHT_GREY","DISABLED_BORDER","BACKGROUND","PRIMARY_LIGHT","PRIMARY","BORDER_LIGHT_COLOR","ToggleComponent","props","ref","_jsxs","_jsx","type","role","aria-checked","checked","span","label","Toggle","React","forwardRef"],"mappings":";;;;;AAIA,MAAMA,MAAAA,iBAASC,MAAAA,CAAAA,OAAAA,EAAAA;;;;AAMf,MAAMC,OAAAA,iBAAQD,MAAAA,CAAAA,OAAAA,EAAAA;;;qJAYcE,aAAAA,CAAcC,UAAAA,CAAWC,UAAU,CAAA,EAAA,+KAAA,EAanCF,aAAAA,CAAcC,WAAWE,eAAe,CAAA,EAAA,sCAAA,EAExCH,cAAcC,UAAAA,CAAWG,UAAU,2DAMnCJ,aAAAA,CAAcC,UAAAA,CAAWI,aAAa,CAAA,EAAA,oEAAA,EAK1CL,aAAAA,CAAcC,WAAWK,OAAO,CAAA,EAAA,uDAAA,EAKxBN,cAAcC,UAAAA,CAAWI,aAAa,qBAC9CL,aAAAA,CAAcC,UAAAA,CAAWK,OAAO,CAAA,EAAA,gDAAA,EAMvCN,aAAAA,CAAcC,WAAWK,OAAO,CAAA,EAAA,4BAAA,EAKhCN,cAAcC,UAAAA,CAAWE,eAAe,4CAI7BH,aAAAA,CAAcC,UAAAA,CAAWC,UAAU,CAAA,EAAA,iEAAA,EAKnCF,aAAAA,CAAcC,WAAWM,kBAAkB,CAAA,EAAA,gBAAA,EAC/CP,aAAAA,CAAcC,UAAAA,CAAWE,eAAe,CAAA,EAAA,IAAA,CAAA;AAShE;;;;AAIC,IACD,SAASK,eAAAA,CAAgBC,KAAkB,EAAEC,GAAgC,EAAA;AACzE,IAAA,qBACIC,IAAA,CAACd,MAAAA,EAAAA;;0BACGe,GAAA,CAACb,OAAAA,EAAAA;AACI,gBAAA,GAAGU,KAAK;gBACTC,GAAAA,EAAKA,GAAAA;gBACLG,IAAAA,EAAK,UAAA;gBACLC,IAAAA,EAAK,QAAA;AACLC,gBAAAA,cAAAA,EAAcN,MAAMO;;0BAExBJ,GAAA,CAACK,MAAAA,EAAAA,EAAAA,CAAAA;0BACDL,GAAA,CAACK,MAAAA,EAAAA;AAAMR,gBAAAA,QAAAA,EAAAA,KAAAA,CAAMS;;;;AAGzB;AAEA,MAAMC,MAAAA,iBAASC,KAAAA,CAAMC,UAAU,CAACb,eAAAA;;;;"}
@@ -5,7 +5,7 @@ import { getThemeValue, THEME_NAME } from '../../shared/constants.js';
5
5
  import MenuContext from './MenuContext.js';
6
6
 
7
7
  const MenuContainer = /*#__PURE__*/ styled("div", {
8
- target: "e1nm0ogj0",
8
+ target: "e1qc23xy0",
9
9
  label: "MenuContainer"
10
10
  })("flex:1;display:flex;flex-direction:column;& div:last-child{border-bottom:none;}&:focus-within{box-shadow:0 0 0 4px ", getThemeValue(THEME_NAME.PRIMARY_LIGHT), ";}");
11
11
  /**
@@ -15,6 +15,11 @@ const MenuContainer = /*#__PURE__*/ styled("div", {
15
15
  * @template T - The type of value(s) in the menu.
16
16
  * @param props - The menu properties.
17
17
  * @param ref - The ref forwarded to the menu container.
18
+ */ /**
19
+ * Menu Component
20
+ * @template T - The type of value(s) in the menu.
21
+ * @param props - Component props
22
+ * @param ref - Ref forwarded to the underlying HTMLDivElement
18
23
  */ function MenuInner(props, ref) {
19
24
  const { multiSelect = false, onChange, value: propValue, children, ...rest } = props;
20
25
  // State holds either a single T or an array of T when multiSelect
@@ -1 +1 @@
1
- {"version":3,"file":"Menu.js","sources":["../../../src/components/Menu/Menu.tsx"],"sourcesContent":["import React, { useState, ForwardedRef } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\nimport MenuContext from './MenuContext';\n/**\n * Props for the Menu component.\n * @template T - The type of value(s) in the menu.\n */\ntype MenuProps<T> = {\n /** Multiple Menu Items can be selected */\n multiSelect?: boolean;\n /** Value(s) selected */\n value?: T | T[];\n /** Callback when the selected value changes */\n onChange?: (value: T | T[]) => void;\n} & Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>;\n\nconst MenuContainer = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n\n & div:last-child {\n border-bottom: none;\n }\n\n &:focus-within {\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n`;\n\n/**\n * Menu component that allows selection of items from a list.\n * Supports single and multi-select modes and keyboard navigation.\n *\n * @template T - The type of value(s) in the menu.\n * @param props - The menu properties.\n * @param ref - The ref forwarded to the menu container.\n */\nfunction MenuInner<T>(props: MenuProps<T>, ref: ForwardedRef<HTMLDivElement>) {\n const { multiSelect = false, onChange, value: propValue, children, ...rest } = props;\n // State holds either a single T or an array of T when multiSelect\n const [value, setValue] = useState<unknown | undefined>(propValue);\n\n /**\n * Updates the selected value(s).\n * Handles both single and multi-select logic.\n *\n * @param {T} val - The value to select or deselect.\n */\n const updateValue = (val: unknown) => {\n let newVal: unknown;\n if (multiSelect) {\n if (Array.isArray(value)) {\n if (value.includes(val as unknown as T)) {\n newVal = (value as T[]).filter((item) => item !== val);\n } else {\n newVal = [...(value as T[]), val];\n }\n } else {\n newVal = [val];\n }\n } else {\n newVal = val;\n }\n\n setValue(newVal as T | T[]);\n onChange?.(newVal as T | T[]);\n };\n\n /**\n * Handles keyboard navigation within the menu.\n * Supports Arrow keys for navigation, and Enter/Space for selection.\n *\n * @param {React.KeyboardEvent} e - The keyboard event.\n */\n const handleKeyDown = (e: React.KeyboardEvent) => {\n const target = e.target as HTMLElement;\n const container = e.currentTarget as HTMLElement;\n const items = Array.from(container.querySelectorAll('[role=\"option\"]')) as HTMLElement[];\n const currentIndex = items.indexOf(target as HTMLElement);\n\n let nextIndex;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n nextIndex = currentIndex + 1;\n if (nextIndex >= items.length) nextIndex = 0;\n items[nextIndex]?.focus();\n break;\n case 'ArrowUp':\n e.preventDefault();\n nextIndex = currentIndex - 1;\n if (nextIndex < 0) nextIndex = items.length - 1;\n items[nextIndex]?.focus();\n break;\n case 'Home':\n e.preventDefault();\n items[0]?.focus();\n break;\n case 'End':\n e.preventDefault();\n items[items.length - 1]?.focus();\n break;\n case 'Enter':\n case ' ': // Space\n e.preventDefault();\n target.click();\n break;\n default:\n break;\n }\n };\n\n /**\n * Handles focus events on the menu container.\n * Delegates focus to the first item if the container itself receives focus.\n *\n * @param {React.FocusEvent} e - The focus event.\n */\n const focusHandler = (e: React.FocusEvent) => {\n // Prevent trap: If focus came from inside (Shift+Tab), do NOT auto-focus again.\n // This allows focus to land on the container, and the next Shift+Tab will exit.\n if (e.currentTarget.contains(e.relatedTarget as Node)) {\n return;\n }\n\n // Only if focus is actually on the container (e.g. tabbing into it)\n // and not bubbling up from a child\n if (e.target === e.currentTarget) {\n // Prevent the container from holding focus; delegate to first item\n const firstItem = e.currentTarget.querySelector('[role=\"option\"]') as HTMLElement;\n firstItem?.focus();\n }\n };\n\n return (\n // @ts-expect-error Generic context typing\n <MenuContext.Provider value={{ value: value, multiSelect: !!multiSelect, updateValue }}>\n <MenuContainer\n {...rest}\n ref={ref}\n role=\"listbox\"\n aria-multiselectable={multiSelect}\n tabIndex={0}\n onKeyDown={handleKeyDown}\n onFocus={focusHandler}\n >\n {children}\n </MenuContainer>\n </MenuContext.Provider>\n );\n}\n\nconst Menu = React.forwardRef(MenuInner) as <T>(\n props: MenuProps<T> & React.RefAttributes<HTMLDivElement>,\n) => React.ReactElement;\n\nexport default Menu;\n"],"names":["MenuContainer","styled","getThemeValue","THEME_NAME","PRIMARY_LIGHT","MenuInner","props","ref","multiSelect","onChange","value","propValue","children","rest","setValue","useState","updateValue","val","newVal","Array","isArray","includes","filter","item","handleKeyDown","e","target","container","currentTarget","items","from","querySelectorAll","currentIndex","indexOf","nextIndex","key","preventDefault","length","focus","click","focusHandler","contains","relatedTarget","firstItem","querySelector","_jsx","MenuContext","Provider","role","aria-multiselectable","tabIndex","onKeyDown","onFocus","Menu","React","forwardRef"],"mappings":"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"}
1
+ {"version":3,"file":"Menu.js","sources":["../../../src/components/Menu/Menu.tsx"],"sourcesContent":["import React, { useState, ForwardedRef } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\nimport MenuContext from './MenuContext';\n/**\n * Props for the Menu component.\n * @template T - The type of value(s) in the menu.\n */\ntype MenuProps<T> = {\n /** Multiple Menu Items can be selected */\n multiSelect?: boolean;\n /** Value(s) selected */\n value?: T | T[];\n /** Callback when the selected value changes */\n onChange?: (value: T | T[]) => void;\n} & Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>;\n\nconst MenuContainer = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n\n & div:last-child {\n border-bottom: none;\n }\n\n &:focus-within {\n box-shadow: 0 0 0 4px ${getThemeValue(THEME_NAME.PRIMARY_LIGHT)};\n }\n`;\n\n/**\n * Menu component that allows selection of items from a list.\n * Supports single and multi-select modes and keyboard navigation.\n *\n * @template T - The type of value(s) in the menu.\n * @param props - The menu properties.\n * @param ref - The ref forwarded to the menu container.\n */\n/**\n * Menu Component\n * @template T - The type of value(s) in the menu.\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLDivElement\n */\nfunction MenuInner<T>(props: MenuProps<T>, ref: ForwardedRef<HTMLDivElement>) {\n const { multiSelect = false, onChange, value: propValue, children, ...rest } = props;\n // State holds either a single T or an array of T when multiSelect\n const [value, setValue] = useState<unknown | undefined>(propValue);\n\n /**\n * Updates the selected value(s).\n * Handles both single and multi-select logic.\n *\n * @param {T} val - The value to select or deselect.\n */\n const updateValue = (val: unknown) => {\n let newVal: unknown;\n if (multiSelect) {\n if (Array.isArray(value)) {\n if (value.includes(val as unknown as T)) {\n newVal = (value as T[]).filter((item) => item !== val);\n } else {\n newVal = [...(value as T[]), val];\n }\n } else {\n newVal = [val];\n }\n } else {\n newVal = val;\n }\n\n setValue(newVal as T | T[]);\n onChange?.(newVal as T | T[]);\n };\n\n /**\n * Handles keyboard navigation within the menu.\n * Supports Arrow keys for navigation, and Enter/Space for selection.\n *\n * @param {React.KeyboardEvent} e - The keyboard event.\n */\n const handleKeyDown = (e: React.KeyboardEvent) => {\n const target = e.target as HTMLElement;\n const container = e.currentTarget as HTMLElement;\n const items = Array.from(container.querySelectorAll('[role=\"option\"]')) as HTMLElement[];\n const currentIndex = items.indexOf(target as HTMLElement);\n\n let nextIndex;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n nextIndex = currentIndex + 1;\n if (nextIndex >= items.length) nextIndex = 0;\n items[nextIndex]?.focus();\n break;\n case 'ArrowUp':\n e.preventDefault();\n nextIndex = currentIndex - 1;\n if (nextIndex < 0) nextIndex = items.length - 1;\n items[nextIndex]?.focus();\n break;\n case 'Home':\n e.preventDefault();\n items[0]?.focus();\n break;\n case 'End':\n e.preventDefault();\n items[items.length - 1]?.focus();\n break;\n case 'Enter':\n case ' ': // Space\n e.preventDefault();\n target.click();\n break;\n default:\n break;\n }\n };\n\n /**\n * Handles focus events on the menu container.\n * Delegates focus to the first item if the container itself receives focus.\n *\n * @param {React.FocusEvent} e - The focus event.\n */\n const focusHandler = (e: React.FocusEvent) => {\n // Prevent trap: If focus came from inside (Shift+Tab), do NOT auto-focus again.\n // This allows focus to land on the container, and the next Shift+Tab will exit.\n if (e.currentTarget.contains(e.relatedTarget as Node)) {\n return;\n }\n\n // Only if focus is actually on the container (e.g. tabbing into it)\n // and not bubbling up from a child\n if (e.target === e.currentTarget) {\n // Prevent the container from holding focus; delegate to first item\n const firstItem = e.currentTarget.querySelector('[role=\"option\"]') as HTMLElement;\n firstItem?.focus();\n }\n };\n\n return (\n // @ts-expect-error Generic context typing\n <MenuContext.Provider value={{ value: value, multiSelect: !!multiSelect, updateValue }}>\n <MenuContainer\n {...rest}\n ref={ref}\n role=\"listbox\"\n aria-multiselectable={multiSelect}\n tabIndex={0}\n onKeyDown={handleKeyDown}\n onFocus={focusHandler}\n >\n {children}\n </MenuContainer>\n </MenuContext.Provider>\n );\n}\n\nconst Menu = React.forwardRef(MenuInner) as <T>(\n props: MenuProps<T> & React.RefAttributes<HTMLDivElement>,\n) => React.ReactElement;\n\nexport default Menu;\n"],"names":["MenuContainer","styled","getThemeValue","THEME_NAME","PRIMARY_LIGHT","MenuInner","props","ref","multiSelect","onChange","value","propValue","children","rest","setValue","useState","updateValue","val","newVal","Array","isArray","includes","filter","item","handleKeyDown","e","target","container","currentTarget","items","from","querySelectorAll","currentIndex","indexOf","nextIndex","key","preventDefault","length","focus","click","focusHandler","contains","relatedTarget","firstItem","querySelector","_jsx","MenuContext","Provider","role","aria-multiselectable","tabIndex","onKeyDown","onFocus","Menu","React","forwardRef"],"mappings":"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"}
@@ -3,6 +3,12 @@ type MenuItemProps<T> = {
3
3
  /** Value of the element */
4
4
  value: T;
5
5
  } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value'>;
6
+ /**
7
+ * MenuItem Component
8
+ * @template T - The type of value in the menu item.
9
+ * @param props - Component props
10
+ * @param ref - Ref forwarded to the underlying HTMLButtonElement
11
+ */
6
12
  declare const MenuItemInner: <T>(props: MenuItemProps<T>, ref: React.Ref<HTMLButtonElement>) => import("@emotion/react/jsx-runtime").JSX.Element;
7
13
  declare const MenuItem: <T>(props: MenuItemProps<T> & {
8
14
  ref?: React.Ref<HTMLButtonElement>;
@@ -6,10 +6,15 @@ import Checkbox from '../Input/Checkbox.js';
6
6
  import MenuContext from './MenuContext.js';
7
7
 
8
8
  const Container$4 = /*#__PURE__*/ styled("button", {
9
- target: "eum9bel0",
9
+ target: "ebwocs30",
10
10
  label: "Container"
11
11
  })("font-weight:", (props)=>props.selected ? 'bold' : 'normal', ";padding:8px;border:none;border-left:4px solid\n ", (props)=>props.selected && !props.multiselect ? getThemeValue(THEME_NAME.TEXT_COLOR_DARK) : 'transparent', ";background-color:transparent;font-size:16px;border-bottom:1px solid ", getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR), ";min-height:41px;display:flex;align-items:center;cursor:pointer;position:relative;color:", getThemeValue(THEME_NAME.TEXT_COLOR_DARK), ";&:hover,&:focus,&:focus-within{background-color:", getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR), ";}& > label{margin:0 4px 0 0;}");
12
- const MenuItemInner = (props, ref)=>{
12
+ /**
13
+ * MenuItem Component
14
+ * @template T - The type of value in the menu item.
15
+ * @param props - Component props
16
+ * @param ref - Ref forwarded to the underlying HTMLButtonElement
17
+ */ const MenuItemInner = (props, ref)=>{
13
18
  const context = useContext(MenuContext);
14
19
  if (!context) {
15
20
  throw new Error('`MenuItem` must be used within a `Menu` provider');
@@ -1 +1 @@
1
- {"version":3,"file":"MenuItem.js","sources":["../../../src/components/Menu/MenuItem.tsx"],"sourcesContent":["import React, { SyntheticEvent, useContext } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\nimport Checkbox from '../Input/Checkbox';\nimport MenuContext, { MenuContextType } from './MenuContext';\n\ntype MenuItemProps<T> = {\n /** Value of the element */\n value: T;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value'>;\n\nconst Container = styled.button<{ selected: boolean; multiselect?: boolean }>`\n font-weight: ${(props) => (props.selected ? 'bold' : 'normal')};\n padding: 8px;\n border: none;\n border-left: 4px solid\n ${(props) =>\n props.selected && !props.multiselect\n ? getThemeValue(THEME_NAME.TEXT_COLOR_DARK)\n : 'transparent'};\n background-color: transparent;\n font-size: 16px;\n border-bottom: 1px solid ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n min-height: 41px;\n display: flex;\n align-items: center;\n cursor: pointer;\n position: relative;\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_DARK)};\n\n &:hover,\n &:focus,\n &:focus-within {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n }\n\n & > label {\n margin: 0 4px 0 0;\n }\n`;\n\nconst MenuItemInner = <T,>(props: MenuItemProps<T>, ref: React.Ref<HTMLButtonElement>) => {\n const context = useContext(MenuContext) as MenuContextType<T> | undefined;\n if (!context) {\n throw new Error('`MenuItem` must be used within a `Menu` provider');\n }\n const { value, children, ...rest } = props;\n const clickHandler = (e: SyntheticEvent) => {\n e.stopPropagation();\n context.updateValue(value as T);\n };\n\n let selected = false;\n if (context.multiSelect) {\n const arr = context.value as unknown as T[] | undefined;\n selected = Array.isArray(arr) && arr.includes(value as unknown as T);\n } else {\n selected = (context.value as unknown as T) === value;\n }\n\n return (\n <Container\n {...rest}\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n selected={selected}\n onClick={clickHandler}\n multiselect={context.multiSelect ? true : undefined}\n >\n {context.multiSelect && (\n <Checkbox\n checked={selected}\n readOnly\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n {children}\n </Container>\n );\n};\n\nconst MenuItem = React.forwardRef(MenuItemInner) as <T>(\n props: MenuItemProps<T> & { ref?: React.Ref<HTMLButtonElement> },\n) => ReturnType<typeof MenuItemInner>;\nexport default MenuItem;\n"],"names":["Container","styled","props","selected","multiselect","getThemeValue","THEME_NAME","TEXT_COLOR_DARK","BORDER_LIGHT_COLOR","MenuItemInner","ref","context","useContext","MenuContext","Error","value","children","rest","clickHandler","e","stopPropagation","updateValue","multiSelect","arr","Array","isArray","includes","_jsxs","type","role","aria-selected","onClick","undefined","_jsx","Checkbox","checked","readOnly","tabIndex","MenuItem","React","forwardRef"],"mappings":";;;;;;;AAWA,MAAMA,WAAAA,iBAAYC,MAAAA,CAAAA,QAAAA,EAAAA;;;AACC,CAAA,CAAA,CAAA,cAAA,EAAA,CAACC,KAAAA,GAAWA,KAAAA,CAAMC,QAAQ,GAAG,MAAA,GAAS,QAAA,EAAA,0DAAA,EAI/C,CAACD,KAAAA,GACCA,KAAAA,CAAMC,QAAQ,IAAI,CAACD,MAAME,WAAW,GAC9BC,aAAAA,CAAcC,UAAAA,CAAWC,eAAe,CAAA,GACxC,aAAA,EAAA,uEAAA,EAGaF,aAAAA,CAAcC,UAAAA,CAAWE,kBAAkB,CAAA,EAAA,0FAAA,EAM7DH,aAAAA,CAAcC,UAAAA,CAAWC,eAAe,CAAA,EAAA,mDAAA,EAKzBF,aAAAA,CAAcC,WAAWE,kBAAkB,CAAA,EAAA,gCAAA,CAAA;AAQvE,MAAMC,aAAAA,GAAgB,CAAKP,KAAAA,EAAyBQ,GAAAA,GAAAA;AAChD,IAAA,MAAMC,UAAUC,UAAAA,CAAWC,WAAAA,CAAAA;AAC3B,IAAA,IAAI,CAACF,OAAAA,EAAS;AACV,QAAA,MAAM,IAAIG,KAAAA,CAAM,kDAAA,CAAA;AACpB,IAAA;AACA,IAAA,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGC,MAAM,GAAGf,KAAAA;AACrC,IAAA,MAAMgB,eAAe,CAACC,CAAAA,GAAAA;AAClBA,QAAAA,CAAAA,CAAEC,eAAe,EAAA;AACjBT,QAAAA,OAAAA,CAAQU,WAAW,CAACN,KAAAA,CAAAA;AACxB,IAAA,CAAA;AAEA,IAAA,IAAIZ,QAAAA,GAAW,KAAA;IACf,IAAIQ,OAAAA,CAAQW,WAAW,EAAE;QACrB,MAAMC,GAAAA,GAAMZ,QAAQI,KAAK;AACzBZ,QAAAA,QAAAA,GAAWqB,MAAMC,OAAO,CAACF,GAAAA,CAAAA,IAAQA,GAAAA,CAAIG,QAAQ,CAACX,KAAAA,CAAAA;IAClD,CAAA,MAAO;QACHZ,QAAAA,GAAYQ,OAAAA,CAAQI,KAAK,KAAsBA,KAAAA;AACnD,IAAA;AAEA,IAAA,qBACIY,IAAA,CAAC3B,WAAAA,EAAAA;AACI,QAAA,GAAGiB,IAAI;QACRP,GAAAA,EAAKA,GAAAA;QACLkB,IAAAA,EAAK,QAAA;QACLC,IAAAA,EAAK,QAAA;QACLC,eAAAA,EAAe3B,QAAAA;QACfA,QAAAA,EAAUA,QAAAA;QACV4B,OAAAA,EAASb,YAAAA;QACTd,WAAAA,EAAaO,OAAAA,CAAQW,WAAW,GAAG,IAAA,GAAOU,SAAAA;;YAEzCrB,OAAAA,CAAQW,WAAW,kBAChBW,GAAA,CAACC,QAAAA,EAAAA;gBACGC,OAAAA,EAAShC,QAAAA;gBACTiC,QAAQ,EAAA,IAAA;AACRC,gBAAAA,QAAAA,EAAU,EAAC;gBACXN,OAAAA,EAAS,CAACZ,CAAAA,GAAMA,CAAAA,CAAEC,eAAe;;AAGxCJ,YAAAA;;;AAGb,CAAA;AAEA,MAAMsB,QAAAA,iBAAWC,KAAAA,CAAMC,UAAU,CAAC/B,aAAAA;;;;"}
1
+ {"version":3,"file":"MenuItem.js","sources":["../../../src/components/Menu/MenuItem.tsx"],"sourcesContent":["import React, { SyntheticEvent, useContext } from 'react';\nimport styled from '@emotion/styled';\nimport { getThemeValue, THEME_NAME } from '../../shared/constants';\nimport Checkbox from '../Input/Checkbox';\nimport MenuContext, { MenuContextType } from './MenuContext';\n\ntype MenuItemProps<T> = {\n /** Value of the element */\n value: T;\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value'>;\n\nconst Container = styled.button<{ selected: boolean; multiselect?: boolean }>`\n font-weight: ${(props) => (props.selected ? 'bold' : 'normal')};\n padding: 8px;\n border: none;\n border-left: 4px solid\n ${(props) =>\n props.selected && !props.multiselect\n ? getThemeValue(THEME_NAME.TEXT_COLOR_DARK)\n : 'transparent'};\n background-color: transparent;\n font-size: 16px;\n border-bottom: 1px solid ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n min-height: 41px;\n display: flex;\n align-items: center;\n cursor: pointer;\n position: relative;\n color: ${getThemeValue(THEME_NAME.TEXT_COLOR_DARK)};\n\n &:hover,\n &:focus,\n &:focus-within {\n background-color: ${getThemeValue(THEME_NAME.BORDER_LIGHT_COLOR)};\n }\n\n & > label {\n margin: 0 4px 0 0;\n }\n`;\n\n/**\n * MenuItem Component\n * @template T - The type of value in the menu item.\n * @param props - Component props\n * @param ref - Ref forwarded to the underlying HTMLButtonElement\n */\nconst MenuItemInner = <T,>(props: MenuItemProps<T>, ref: React.Ref<HTMLButtonElement>) => {\n const context = useContext(MenuContext) as MenuContextType<T> | undefined;\n if (!context) {\n throw new Error('`MenuItem` must be used within a `Menu` provider');\n }\n const { value, children, ...rest } = props;\n const clickHandler = (e: SyntheticEvent) => {\n e.stopPropagation();\n context.updateValue(value as T);\n };\n\n let selected = false;\n if (context.multiSelect) {\n const arr = context.value as unknown as T[] | undefined;\n selected = Array.isArray(arr) && arr.includes(value as unknown as T);\n } else {\n selected = (context.value as unknown as T) === value;\n }\n\n return (\n <Container\n {...rest}\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n selected={selected}\n onClick={clickHandler}\n multiselect={context.multiSelect ? true : undefined}\n >\n {context.multiSelect && (\n <Checkbox\n checked={selected}\n readOnly\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n {children}\n </Container>\n );\n};\n\nconst MenuItem = React.forwardRef(MenuItemInner) as <T>(\n props: MenuItemProps<T> & { ref?: React.Ref<HTMLButtonElement> },\n) => ReturnType<typeof MenuItemInner>;\nexport default MenuItem;\n"],"names":["Container","styled","props","selected","multiselect","getThemeValue","THEME_NAME","TEXT_COLOR_DARK","BORDER_LIGHT_COLOR","MenuItemInner","ref","context","useContext","MenuContext","Error","value","children","rest","clickHandler","e","stopPropagation","updateValue","multiSelect","arr","Array","isArray","includes","_jsxs","type","role","aria-selected","onClick","undefined","_jsx","Checkbox","checked","readOnly","tabIndex","MenuItem","React","forwardRef"],"mappings":";;;;;;;AAWA,MAAMA,WAAAA,iBAAYC,MAAAA,CAAAA,QAAAA,EAAAA;;;AACC,CAAA,CAAA,CAAA,cAAA,EAAA,CAACC,KAAAA,GAAWA,KAAAA,CAAMC,QAAQ,GAAG,MAAA,GAAS,QAAA,EAAA,0DAAA,EAI/C,CAACD,KAAAA,GACCA,KAAAA,CAAMC,QAAQ,IAAI,CAACD,MAAME,WAAW,GAC9BC,aAAAA,CAAcC,UAAAA,CAAWC,eAAe,CAAA,GACxC,aAAA,EAAA,uEAAA,EAGaF,aAAAA,CAAcC,UAAAA,CAAWE,kBAAkB,CAAA,EAAA,0FAAA,EAM7DH,aAAAA,CAAcC,UAAAA,CAAWC,eAAe,CAAA,EAAA,mDAAA,EAKzBF,aAAAA,CAAcC,WAAWE,kBAAkB,CAAA,EAAA,gCAAA,CAAA;AAQvE;;;;;IAMA,MAAMC,aAAAA,GAAgB,CAAKP,KAAAA,EAAyBQ,GAAAA,GAAAA;AAChD,IAAA,MAAMC,UAAUC,UAAAA,CAAWC,WAAAA,CAAAA;AAC3B,IAAA,IAAI,CAACF,OAAAA,EAAS;AACV,QAAA,MAAM,IAAIG,KAAAA,CAAM,kDAAA,CAAA;AACpB,IAAA;AACA,IAAA,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGC,MAAM,GAAGf,KAAAA;AACrC,IAAA,MAAMgB,eAAe,CAACC,CAAAA,GAAAA;AAClBA,QAAAA,CAAAA,CAAEC,eAAe,EAAA;AACjBT,QAAAA,OAAAA,CAAQU,WAAW,CAACN,KAAAA,CAAAA;AACxB,IAAA,CAAA;AAEA,IAAA,IAAIZ,QAAAA,GAAW,KAAA;IACf,IAAIQ,OAAAA,CAAQW,WAAW,EAAE;QACrB,MAAMC,GAAAA,GAAMZ,QAAQI,KAAK;AACzBZ,QAAAA,QAAAA,GAAWqB,MAAMC,OAAO,CAACF,GAAAA,CAAAA,IAAQA,GAAAA,CAAIG,QAAQ,CAACX,KAAAA,CAAAA;IAClD,CAAA,MAAO;QACHZ,QAAAA,GAAYQ,OAAAA,CAAQI,KAAK,KAAsBA,KAAAA;AACnD,IAAA;AAEA,IAAA,qBACIY,IAAA,CAAC3B,WAAAA,EAAAA;AACI,QAAA,GAAGiB,IAAI;QACRP,GAAAA,EAAKA,GAAAA;QACLkB,IAAAA,EAAK,QAAA;QACLC,IAAAA,EAAK,QAAA;QACLC,eAAAA,EAAe3B,QAAAA;QACfA,QAAAA,EAAUA,QAAAA;QACV4B,OAAAA,EAASb,YAAAA;QACTd,WAAAA,EAAaO,OAAAA,CAAQW,WAAW,GAAG,IAAA,GAAOU,SAAAA;;YAEzCrB,OAAAA,CAAQW,WAAW,kBAChBW,GAAA,CAACC,QAAAA,EAAAA;gBACGC,OAAAA,EAAShC,QAAAA;gBACTiC,QAAQ,EAAA,IAAA;AACRC,gBAAAA,QAAAA,EAAU,EAAC;gBACXN,OAAAA,EAAS,CAACZ,CAAAA,GAAMA,CAAAA,CAAEC,eAAe;;AAGxCJ,YAAAA;;;AAGb,CAAA;AAEA,MAAMsB,QAAAA,iBAAWC,KAAAA,CAAMC,UAAU,CAAC/B,aAAAA;;;;"}
@@ -9,7 +9,7 @@ type ModalProps = {
9
9
  closeOnOverlayClick?: boolean;
10
10
  /** Call back function called when the modal closes. */
11
11
  onClose?: () => void;
12
- /** Ref forwarded to the modal container */
12
+ /** Ref forwarded to the underlying HTMLDivElement of the modal container */
13
13
  forwardRef?: React.Ref<HTMLDivElement>;
14
14
  } & React.HTMLAttributes<HTMLDivElement>;
15
15
  interface ModalState {
@@ -63,6 +63,10 @@ export default class Modal extends React.Component<React.PropsWithChildren<Modal
63
63
  * Lifecycle method to save the currently focused element when the modal mounts while open.
64
64
  */
65
65
  componentDidMount(): void;
66
+ /**
67
+ * Handles opening the modal by creating the layer.
68
+ */
69
+ private handleOpen;
66
70
  /**
67
71
  * Lifecycle method to restore focus when the modal unmounts.
68
72
  */
@@ -85,7 +89,7 @@ export default class Modal extends React.Component<React.PropsWithChildren<Modal
85
89
  * Lifecycle method to handle Modal updates.
86
90
  * Manages opening/closing logic via LayerManager and focus preservation.
87
91
  */
88
- getSnapshotBeforeUpdate(prevProps: ModalProps): void;
92
+ getSnapshotBeforeUpdate(prevProps: ModalProps): null;
89
93
  /**
90
94
  * Renders the Modal component via the LayerManager portal.
91
95
  */
@@ -19,6 +19,8 @@ class Modal extends React.Component {
19
19
  */ componentDidMount() {
20
20
  if (this.props.open) {
21
21
  this.lastFocusedElement = document.activeElement;
22
+ // Handle initial open state
23
+ this.handleOpen();
22
24
  }
23
25
  }
24
26
  /**
@@ -38,7 +40,7 @@ class Modal extends React.Component {
38
40
  * Lifecycle method to handle Modal updates.
39
41
  * Manages opening/closing logic via LayerManager and focus preservation.
40
42
  */ getSnapshotBeforeUpdate(prevProps) {
41
- const { open, closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;
43
+ const { open } = this.props;
42
44
  if (prevProps.open && !open) {
43
45
  this.closeCallback?.();
44
46
  this.restoreFocus();
@@ -46,28 +48,9 @@ class Modal extends React.Component {
46
48
  if (!prevProps.open && open) {
47
49
  // Save current focus
48
50
  this.lastFocusedElement = document.activeElement;
49
- this.layer = LayerManager.renderLayer({
50
- overlay: true,
51
- exitDelay: 300,
52
- position: LAYER_POSITION.DIALOG,
53
- closeCallback: this.onClose,
54
- closeOnEsc: closeOnEsc,
55
- closeOnOverlayClick: closeOnOverlayClick,
56
- component: /*#__PURE__*/ jsx(DialogContainer, {
57
- ...rest,
58
- ref: this.setModalRef,
59
- role: "dialog",
60
- "aria-modal": "true",
61
- tabIndex: -1,
62
- onKeyDown: this.handleKeyDown,
63
- onClick: (e)=>e.stopPropagation(),
64
- elevated: true,
65
- children: children
66
- })
67
- });
68
- this.closeCallback = this.layer[1];
69
- this.forceUpdate();
51
+ this.handleOpen();
70
52
  }
53
+ return null;
71
54
  }
72
55
  /**
73
56
  * Renders the Modal component via the LayerManager portal.
@@ -119,6 +102,31 @@ class Modal extends React.Component {
119
102
  }
120
103
  }
121
104
  }, /**
105
+ * Handles opening the modal by creating the layer.
106
+ */ this.handleOpen = ()=>{
107
+ const { closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;
108
+ this.layer = LayerManager.renderLayer({
109
+ overlay: true,
110
+ exitDelay: 300,
111
+ position: LAYER_POSITION.DIALOG,
112
+ closeCallback: this.onClose,
113
+ closeOnEsc: closeOnEsc,
114
+ closeOnOverlayClick: closeOnOverlayClick,
115
+ component: /*#__PURE__*/ jsx(DialogContainer, {
116
+ ...rest,
117
+ ref: this.setModalRef,
118
+ role: "dialog",
119
+ "aria-modal": "true",
120
+ tabIndex: -1,
121
+ onKeyDown: this.handleKeyDown,
122
+ onClick: (e)=>e.stopPropagation(),
123
+ elevated: true,
124
+ children: children
125
+ })
126
+ });
127
+ this.closeCallback = this.layer[1];
128
+ this.forceUpdate();
129
+ }, /**
122
130
  * Restores focus to the element that was focused before the modal opened.
123
131
  */ this.restoreFocus = ()=>{
124
132
  if (this.lastFocusedElement) {
@@ -142,11 +150,7 @@ class Modal extends React.Component {
142
150
  this.setInitialFocus(node);
143
151
  }
144
152
  if (this.props.forwardRef) {
145
- try {
146
- this.props.forwardRef.current = node;
147
- } catch (e) {
148
- console.warn(e);
149
- }
153
+ this.props.forwardRef.current = node;
150
154
  }
151
155
  }, /**
152
156
  * Sets initial focus within the modal.
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nexport {\n Header as ModalHeader,\n Body as ModalBody,\n Footer as ModalFooter,\n} from '../../shared/styles';\nimport { DialogContainer as ModalContainer } from '../Dialog/Dialog';\n\ntype ModalProps = {\n /** Opens the modal */\n open: boolean;\n /** Closes the modal on esc */\n closeOnEsc?: boolean;\n /** Closes the modal on overlay click */\n closeOnOverlayClick?: boolean;\n /** Call back function called when the modal closes. */\n onClose?: () => void;\n /** Ref forwarded to the modal container */\n forwardRef?: React.Ref<HTMLDivElement>;\n} & React.HTMLAttributes<HTMLDivElement>;\n\ninterface ModalState {\n open: boolean;\n}\n\n/**\n * Modal component\n *\n * A dialog window that sits on top of the main application content.\n * It disrupts the user's workflow to demand attention for a critical task or decision.\n *\n * Accessibility:\n * - Implements ARIA `role=\"dialog\"` and `aria-modal=\"true\"`.\n * - Traps focus effectively within the modal while open.\n * - Restores focus to the triggering element upon closure.\n * - Supports closing via ESC key and overlay click.\n */\nexport default class Modal extends React.Component<\n React.PropsWithChildren<ModalProps>,\n ModalState\n> {\n state = {\n open: false,\n };\n\n static defaultProps = {\n closeOnEsc: true,\n closeOnOverlayClick: true,\n };\n\n /**\n * Syncs state with props.\n */\n static getDerivedStateFromProps(props: ModalProps) {\n if (props.open) {\n return {\n open: true,\n };\n }\n return null;\n }\n\n private layer?: ReturnType<typeof LayerManager.renderLayer>;\n\n private closeCallback?: (resp?: unknown) => void;\n\n /**\n * Internal close handler.\n * Restores focus and calls the external onClose callback.\n */\n private onClose = () => {\n this.restoreFocus();\n this.setState({\n open: false,\n });\n this.props.onClose?.();\n this.closeCallback = undefined;\n this.layer = undefined;\n };\n\n private lastFocusedElement: HTMLElement | null = null;\n private modalRef = React.createRef<HTMLDivElement>();\n\n /**\n * Retrieves all focusable elements within the modal.\n */\n private getFocusableElements = (): HTMLElement[] => {\n if (!this.modalRef.current) return [];\n return Array.from(\n this.modalRef.current.querySelectorAll(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n ),\n ) as HTMLElement[];\n };\n\n /**\n * Handles keydown events to implement the focus trap.\n * Traps Tab and Shift+Tab within the modal.\n */\n private handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Tab') {\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length === 0) return;\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n\n /**\n * Lifecycle method to save the currently focused element when the modal mounts while open.\n */\n componentDidMount() {\n if (this.props.open) {\n this.lastFocusedElement = document.activeElement as HTMLElement;\n }\n }\n\n /**\n * Lifecycle method to restore focus when the modal unmounts.\n */\n componentWillUnmount() {\n if (this.props.open) {\n this.restoreFocus();\n }\n // Clean up layer references\n if (this.closeCallback) {\n this.closeCallback();\n this.closeCallback = undefined;\n }\n this.layer = undefined;\n }\n\n /**\n * Restores focus to the element that was focused before the modal opened.\n */\n private restoreFocus = () => {\n if (this.lastFocusedElement) {\n // Check if the element is still in the document\n const elementToBeFocused = this.lastFocusedElement;\n this.lastFocusedElement = null;\n setTimeout(() => {\n if (document.body.contains(elementToBeFocused)) {\n elementToBeFocused.focus();\n }\n }, 100);\n }\n };\n\n /**\n * Callback ref to capture the Modal DOM element.\n * Triggers initial focus setting when the element mounts.\n */\n private setModalRef = (node: HTMLDivElement | null) => {\n // Update ref\n (this.modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n\n if (node) {\n // Set initial focus when the node is mounted\n this.setInitialFocus(node);\n }\n\n if (this.props.forwardRef) {\n try {\n (this.props.forwardRef as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n } catch (e) {\n console.warn(e);\n }\n }\n };\n\n /**\n * Sets initial focus within the modal.\n * Tries to focus the header (first child) first, then the first interactive element, or falls back to the container.\n */\n private setInitialFocus = (root: HTMLElement) => {\n // Try to find the header (assumed to be the first child)\n const firstChild = root.firstElementChild as HTMLElement;\n if (firstChild) {\n // Ensure it's focusable\n if (firstChild.getAttribute('tabindex') === null) {\n firstChild.setAttribute('tabindex', '-1');\n }\n firstChild.focus();\n return;\n }\n\n // Fallback to focusable elements\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length > 0) {\n focusableElements[0].focus();\n } else {\n // Fallback to container\n root.focus();\n }\n };\n\n /**\n * Lifecycle method to handle Modal updates.\n * Manages opening/closing logic via LayerManager and focus preservation.\n */\n getSnapshotBeforeUpdate(prevProps: ModalProps) {\n const { open, closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;\n\n if (prevProps.open && !open) {\n this.closeCallback?.();\n this.restoreFocus();\n }\n\n if (!prevProps.open && open) {\n // Save current focus\n this.lastFocusedElement = document.activeElement as HTMLElement;\n\n this.layer = LayerManager.renderLayer({\n overlay: true,\n exitDelay: 300,\n position: LAYER_POSITION.DIALOG,\n closeCallback: this.onClose,\n closeOnEsc: closeOnEsc,\n closeOnOverlayClick: closeOnOverlayClick,\n component: (\n <ModalContainer\n {...rest}\n ref={this.setModalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n onKeyDown={this.handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n elevated\n >\n {children}\n </ModalContainer>\n ),\n });\n this.closeCallback = this.layer[1];\n this.forceUpdate();\n }\n }\n\n /**\n * Renders the Modal component via the LayerManager portal.\n */\n render() {\n if (this.state.open && this.layer) {\n const [Component] = this.layer;\n return <Component />;\n }\n\n return null;\n }\n}\n"],"names":["Modal","React","Component","getDerivedStateFromProps","props","open","componentDidMount","lastFocusedElement","document","activeElement","componentWillUnmount","restoreFocus","closeCallback","undefined","layer","getSnapshotBeforeUpdate","prevProps","closeOnEsc","closeOnOverlayClick","children","rest","LayerManager","renderLayer","overlay","exitDelay","position","LAYER_POSITION","DIALOG","onClose","component","_jsx","ModalContainer","ref","setModalRef","role","aria-modal","tabIndex","onKeyDown","handleKeyDown","onClick","e","stopPropagation","elevated","forceUpdate","render","state","setState","modalRef","createRef","getFocusableElements","current","Array","from","querySelectorAll","key","focusableElements","length","firstElement","lastElement","shiftKey","focus","preventDefault","elementToBeFocused","setTimeout","body","contains","node","setInitialFocus","forwardRef","console","warn","root","firstChild","firstElementChild","getAttribute","setAttribute","defaultProps"],"mappings":"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"}
1
+ {"version":3,"file":"Modal.js","sources":["../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nexport {\n Header as ModalHeader,\n Body as ModalBody,\n Footer as ModalFooter,\n} from '../../shared/styles';\nimport { DialogContainer as ModalContainer } from '../Dialog/Dialog';\n\ntype ModalProps = {\n /** Opens the modal */\n open: boolean;\n /** Closes the modal on esc */\n closeOnEsc?: boolean;\n /** Closes the modal on overlay click */\n closeOnOverlayClick?: boolean;\n /** Call back function called when the modal closes. */\n onClose?: () => void;\n /** Ref forwarded to the underlying HTMLDivElement of the modal container */\n forwardRef?: React.Ref<HTMLDivElement>;\n} & React.HTMLAttributes<HTMLDivElement>;\n\ninterface ModalState {\n open: boolean;\n}\n\n/**\n * Modal component\n *\n * A dialog window that sits on top of the main application content.\n * It disrupts the user's workflow to demand attention for a critical task or decision.\n *\n * Accessibility:\n * - Implements ARIA `role=\"dialog\"` and `aria-modal=\"true\"`.\n * - Traps focus effectively within the modal while open.\n * - Restores focus to the triggering element upon closure.\n * - Supports closing via ESC key and overlay click.\n */\nexport default class Modal extends React.Component<\n React.PropsWithChildren<ModalProps>,\n ModalState\n> {\n state = {\n open: false,\n };\n\n static defaultProps = {\n closeOnEsc: true,\n closeOnOverlayClick: true,\n };\n\n /**\n * Syncs state with props.\n */\n static getDerivedStateFromProps(props: ModalProps) {\n if (props.open) {\n return {\n open: true,\n };\n }\n return null;\n }\n\n private layer?: ReturnType<typeof LayerManager.renderLayer>;\n\n private closeCallback?: (resp?: unknown) => void;\n\n /**\n * Internal close handler.\n * Restores focus and calls the external onClose callback.\n */\n private onClose = () => {\n this.restoreFocus();\n this.setState({\n open: false,\n });\n this.props.onClose?.();\n this.closeCallback = undefined;\n this.layer = undefined;\n };\n\n private lastFocusedElement: HTMLElement | null = null;\n private modalRef = React.createRef<HTMLDivElement>();\n\n /**\n * Retrieves all focusable elements within the modal.\n */\n private getFocusableElements = (): HTMLElement[] => {\n if (!this.modalRef.current) return [];\n return Array.from(\n this.modalRef.current.querySelectorAll(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n ),\n ) as HTMLElement[];\n };\n\n /**\n * Handles keydown events to implement the focus trap.\n * Traps Tab and Shift+Tab within the modal.\n */\n private handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Tab') {\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length === 0) return;\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n\n /**\n * Lifecycle method to save the currently focused element when the modal mounts while open.\n */\n componentDidMount() {\n if (this.props.open) {\n this.lastFocusedElement = document.activeElement as HTMLElement;\n // Handle initial open state\n this.handleOpen();\n }\n }\n\n /**\n * Handles opening the modal by creating the layer.\n */\n private handleOpen = () => {\n const { closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;\n\n this.layer = LayerManager.renderLayer({\n overlay: true,\n exitDelay: 300,\n position: LAYER_POSITION.DIALOG,\n closeCallback: this.onClose,\n closeOnEsc: closeOnEsc,\n closeOnOverlayClick: closeOnOverlayClick,\n component: (\n <ModalContainer\n {...rest}\n ref={this.setModalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n onKeyDown={this.handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n elevated\n >\n {children}\n </ModalContainer>\n ),\n });\n this.closeCallback = this.layer[1];\n this.forceUpdate();\n };\n\n /**\n * Lifecycle method to restore focus when the modal unmounts.\n */\n componentWillUnmount() {\n if (this.props.open) {\n this.restoreFocus();\n }\n // Clean up layer references\n if (this.closeCallback) {\n this.closeCallback();\n this.closeCallback = undefined;\n }\n this.layer = undefined;\n }\n\n /**\n * Restores focus to the element that was focused before the modal opened.\n */\n private restoreFocus = () => {\n if (this.lastFocusedElement) {\n // Check if the element is still in the document\n const elementToBeFocused = this.lastFocusedElement;\n this.lastFocusedElement = null;\n setTimeout(() => {\n if (document.body.contains(elementToBeFocused)) {\n elementToBeFocused.focus();\n }\n }, 100);\n }\n };\n\n /**\n * Callback ref to capture the Modal DOM element.\n * Triggers initial focus setting when the element mounts.\n */\n private setModalRef = (node: HTMLDivElement | null) => {\n // Update ref\n (this.modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n\n if (node) {\n // Set initial focus when the node is mounted\n this.setInitialFocus(node);\n }\n\n if (this.props.forwardRef) {\n (this.props.forwardRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }\n };\n\n /**\n * Sets initial focus within the modal.\n * Tries to focus the header (first child) first, then the first interactive element, or falls back to the container.\n */\n private setInitialFocus = (root: HTMLElement) => {\n // Try to find the header (assumed to be the first child)\n const firstChild = root.firstElementChild as HTMLElement;\n if (firstChild) {\n // Ensure it's focusable\n if (firstChild.getAttribute('tabindex') === null) {\n firstChild.setAttribute('tabindex', '-1');\n }\n firstChild.focus();\n return;\n }\n\n // Fallback to focusable elements\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length > 0) {\n focusableElements[0].focus();\n } else {\n // Fallback to container\n root.focus();\n }\n };\n\n /**\n * Lifecycle method to handle Modal updates.\n * Manages opening/closing logic via LayerManager and focus preservation.\n */\n getSnapshotBeforeUpdate(prevProps: ModalProps) {\n const { open } = this.props;\n\n if (prevProps.open && !open) {\n this.closeCallback?.();\n this.restoreFocus();\n }\n\n if (!prevProps.open && open) {\n // Save current focus\n this.lastFocusedElement = document.activeElement as HTMLElement;\n this.handleOpen();\n }\n\n return null;\n }\n\n /**\n * Renders the Modal component via the LayerManager portal.\n */\n render() {\n if (this.state.open && this.layer) {\n const [Component] = this.layer;\n return <Component />;\n }\n\n return null;\n }\n}\n"],"names":["Modal","React","Component","getDerivedStateFromProps","props","open","componentDidMount","lastFocusedElement","document","activeElement","handleOpen","componentWillUnmount","restoreFocus","closeCallback","undefined","layer","getSnapshotBeforeUpdate","prevProps","render","state","_jsx","onClose","setState","modalRef","createRef","getFocusableElements","current","Array","from","querySelectorAll","handleKeyDown","e","key","focusableElements","length","firstElement","lastElement","shiftKey","focus","preventDefault","closeOnEsc","closeOnOverlayClick","children","rest","LayerManager","renderLayer","overlay","exitDelay","position","LAYER_POSITION","DIALOG","component","ModalContainer","ref","setModalRef","role","aria-modal","tabIndex","onKeyDown","onClick","stopPropagation","elevated","forceUpdate","elementToBeFocused","setTimeout","body","contains","node","setInitialFocus","forwardRef","root","firstChild","firstElementChild","getAttribute","setAttribute","defaultProps"],"mappings":"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"}
@@ -40,6 +40,8 @@ export declare function StoryProps(props: NotificationProps): null;
40
40
  declare class Notification {
41
41
  /** Helps in maintaining single instance for different positions. */
42
42
  private containers;
43
+ /** Pending add requests waiting for manager to mount */
44
+ private pending;
43
45
  /**
44
46
  * Adds a notification
45
47
  *
@@ -14,6 +14,7 @@ import { NOTIFICATION_POSITION } from './types.js';
14
14
  /** Notification class */ class Notification {
15
15
  constructor(){
16
16
  /** Helps in maintaining single instance for different positions. */ this.containers = new Map();
17
+ /** Pending add requests waiting for manager to mount */ this.pending = new Map();
17
18
  /**
18
19
  * Adds a notification
19
20
  *
@@ -28,6 +29,12 @@ import { NOTIFICATION_POSITION } from './types.js';
28
29
  if (container) {
29
30
  container.manager = instance;
30
31
  }
32
+ // Process pending requests
33
+ const queue = this.pending.get(position);
34
+ if (queue) {
35
+ queue.forEach((cb)=>cb(instance));
36
+ this.pending.delete(position);
37
+ }
31
38
  }
32
39
  };
33
40
  const [Component] = LayerManager.renderLayer({
@@ -60,14 +67,13 @@ import { NOTIFICATION_POSITION } from './types.js';
60
67
  if (container && container.manager) {
61
68
  return container.manager.add(options);
62
69
  }
63
- // If manager is not ready yet, wait a bit and retry
70
+ // If manager is not ready yet, add to pending queue
64
71
  return new Promise((resolve)=>{
65
- setTimeout(()=>{
66
- const container = this.containers.get(position);
67
- if (container && container.manager) {
68
- resolve(container.manager.add(options));
69
- }
70
- }, 10);
72
+ const queue = this.pending.get(position) || [];
73
+ queue.push((manager)=>{
74
+ resolve(manager.add(options));
75
+ });
76
+ this.pending.set(position, queue);
71
77
  });
72
78
  };
73
79
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.js","sources":["../../../src/components/Notification/Notification.tsx"],"sourcesContent":["import { type RefCallback } from 'react';\nimport { flushSync } from 'react-dom';\nimport { createRoot, type Root } from 'react-dom/client';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nimport NotificationManager from './NotificationManager';\nimport { NOTIFICATION_POSITION, NOTIFICATION_TYPE, NotificationOptions } from './types';\n\ntype NotificationProps = {\n /** Title of the notification */\n title: string;\n /** Body of the notification */\n description: string;\n /** Id for the notification, helps in de-duplication. */\n id?: string;\n /**\n * Duration for the notification in milliseconds\n * @default 5000\n */\n duration?: number;\n /**\n * Creates sticky notification\n * @default false\n */\n sticky?: boolean;\n /**\n * Type of notification\n * @default NOTIFICATION_TYPE.INFO\n */\n type?: NOTIFICATION_TYPE;\n /** Action button text */\n buttonText?: string;\n /** Action button click callback */\n buttonClick?: () => void;\n /** Notification close callback. */\n onClose?: () => void;\n /** Aria label for the close button on the notification. Defaults to \"Close notification\" */\n closeButtonAriaLabel?: string;\n};\n\n/**\n * This dummy component is used to extract props for documentation in Storybook.\n * @param props\n * @returns\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function StoryProps(props: NotificationProps) {\n return null;\n}\n\n/** Maps notification position to layer position */\nconst positionMap = {\n [NOTIFICATION_POSITION.TOP_LEFT]: LAYER_POSITION.TOP_LEFT,\n [NOTIFICATION_POSITION.TOP_RIGHT]: LAYER_POSITION.TOP_RIGHT,\n [NOTIFICATION_POSITION.BOTTOM_LEFT]: LAYER_POSITION.BOTTOM_LEFT,\n [NOTIFICATION_POSITION.BOTTOM_RIGHT]: LAYER_POSITION.BOTTOM_RIGHT,\n};\n\n/** Notification class */\nclass Notification {\n /** Helps in maintaining single instance for different positions. */\n private containers: Map<\n NOTIFICATION_POSITION,\n {\n manager: NotificationManager | null;\n root: Root;\n div: HTMLDivElement;\n }\n > = new Map();\n\n /**\n * Adds a notification\n *\n * @param position - The position where the notification should appear\n * @param options - Configuration options for the notification\n * @returns The notification ID or a promise that resolves to the notification ID\n */\n public add = (\n position: NOTIFICATION_POSITION,\n options: NotificationOptions,\n ariaLabel: string = 'Notifications',\n ) => {\n if (!this.containers.has(position)) {\n /** Callback ref to capture the NotificationManager instance when it mounts */\n const refCallback: RefCallback<NotificationManager> = (instance) => {\n if (instance) {\n const container = this.containers.get(position);\n if (container) {\n container.manager = instance;\n }\n }\n };\n\n const [Component] = LayerManager.renderLayer({\n closeOnEsc: false,\n closeOnOverlayClick: false,\n position: positionMap[position],\n alwaysOnTop: true,\n component: (\n <NotificationManager\n ref={refCallback}\n position={position}\n onEmpty={() => this.destroy(position)}\n ariaLabel={ariaLabel}\n />\n ),\n });\n\n // Create a div to mount the Component\n const div = document.createElement('div');\n document.body.appendChild(div);\n const root = createRoot(div);\n\n this.containers.set(position, {\n manager: null,\n root,\n div,\n });\n\n // Render the Component which will trigger the LayerManager's useEffect\n flushSync(() => {\n root.render(<Component />);\n });\n }\n\n const container = this.containers.get(position);\n if (container && container.manager) {\n return container.manager.add(options);\n }\n\n // If manager is not ready yet, wait a bit and retry\n return new Promise<string>((resolve) => {\n setTimeout(() => {\n const container = this.containers.get(position);\n if (container && container.manager) {\n resolve(container.manager.add(options));\n }\n }, 10);\n });\n };\n\n /**\n * Removes a notification\n *\n * @param position - The position of the notification container\n * @param id - The unique ID of the notification to remove\n */\n public remove = (position: NOTIFICATION_POSITION, id: string) => {\n const container = this.containers.get(position);\n if (container && container.manager) {\n container.manager.remove(id);\n }\n };\n\n /**\n * Destroys entire stack of notifications at a position.\n * Unmounts the React root and cleans up DOM elements.\n *\n * @param position - The position of the notification container to destroy\n */\n public destroy = (position: NOTIFICATION_POSITION) => {\n const container = this.containers.get(position);\n if (container) {\n container.root.unmount();\n if (document.body.contains(container.div)) {\n document.body.removeChild(container.div);\n }\n this.containers.delete(position);\n }\n };\n}\n\n/** Export a singleton instance */\nexport default new Notification();\n"],"names":["positionMap","NOTIFICATION_POSITION","TOP_LEFT","LAYER_POSITION","TOP_RIGHT","BOTTOM_LEFT","BOTTOM_RIGHT","Notification","containers","Map","add","position","options","ariaLabel","has","refCallback","instance","container","get","manager","Component","LayerManager","renderLayer","closeOnEsc","closeOnOverlayClick","alwaysOnTop","component","_jsx","NotificationManager","ref","onEmpty","destroy","div","document","createElement","body","appendChild","root","createRoot","set","flushSync","render","Promise","resolve","setTimeout","remove","id","unmount","contains","removeChild","delete"],"mappings":"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"}
1
+ {"version":3,"file":"Notification.js","sources":["../../../src/components/Notification/Notification.tsx"],"sourcesContent":["import { type RefCallback } from 'react';\nimport { flushSync } from 'react-dom';\nimport { createRoot, type Root } from 'react-dom/client';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nimport NotificationManager from './NotificationManager';\nimport { NOTIFICATION_POSITION, NOTIFICATION_TYPE, NotificationOptions } from './types';\n\ntype NotificationProps = {\n /** Title of the notification */\n title: string;\n /** Body of the notification */\n description: string;\n /** Id for the notification, helps in de-duplication. */\n id?: string;\n /**\n * Duration for the notification in milliseconds\n * @default 5000\n */\n duration?: number;\n /**\n * Creates sticky notification\n * @default false\n */\n sticky?: boolean;\n /**\n * Type of notification\n * @default NOTIFICATION_TYPE.INFO\n */\n type?: NOTIFICATION_TYPE;\n /** Action button text */\n buttonText?: string;\n /** Action button click callback */\n buttonClick?: () => void;\n /** Notification close callback. */\n onClose?: () => void;\n /** Aria label for the close button on the notification. Defaults to \"Close notification\" */\n closeButtonAriaLabel?: string;\n};\n\n/**\n * This dummy component is used to extract props for documentation in Storybook.\n * @param props\n * @returns\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function StoryProps(props: NotificationProps) {\n return null;\n}\n\n/** Maps notification position to layer position */\nconst positionMap = {\n [NOTIFICATION_POSITION.TOP_LEFT]: LAYER_POSITION.TOP_LEFT,\n [NOTIFICATION_POSITION.TOP_RIGHT]: LAYER_POSITION.TOP_RIGHT,\n [NOTIFICATION_POSITION.BOTTOM_LEFT]: LAYER_POSITION.BOTTOM_LEFT,\n [NOTIFICATION_POSITION.BOTTOM_RIGHT]: LAYER_POSITION.BOTTOM_RIGHT,\n};\n\n/** Notification class */\nclass Notification {\n /** Helps in maintaining single instance for different positions. */\n private containers: Map<\n NOTIFICATION_POSITION,\n {\n manager: NotificationManager | null;\n root: Root;\n div: HTMLDivElement;\n }\n > = new Map();\n\n /** Pending add requests waiting for manager to mount */\n private pending: Map<NOTIFICATION_POSITION, Array<(manager: NotificationManager) => void>> =\n new Map();\n\n /**\n * Adds a notification\n *\n * @param position - The position where the notification should appear\n * @param options - Configuration options for the notification\n * @returns The notification ID or a promise that resolves to the notification ID\n */\n public add = (\n position: NOTIFICATION_POSITION,\n options: NotificationOptions,\n ariaLabel: string = 'Notifications',\n ) => {\n if (!this.containers.has(position)) {\n /** Callback ref to capture the NotificationManager instance when it mounts */\n const refCallback: RefCallback<NotificationManager> = (instance) => {\n if (instance) {\n const container = this.containers.get(position);\n if (container) {\n container.manager = instance;\n }\n\n // Process pending requests\n const queue = this.pending.get(position);\n if (queue) {\n queue.forEach((cb) => cb(instance));\n this.pending.delete(position);\n }\n }\n };\n\n const [Component] = LayerManager.renderLayer({\n closeOnEsc: false,\n closeOnOverlayClick: false,\n position: positionMap[position],\n alwaysOnTop: true,\n component: (\n <NotificationManager\n ref={refCallback}\n position={position}\n onEmpty={() => this.destroy(position)}\n ariaLabel={ariaLabel}\n />\n ),\n });\n\n // Create a div to mount the Component\n const div = document.createElement('div');\n document.body.appendChild(div);\n const root = createRoot(div);\n\n this.containers.set(position, {\n manager: null,\n root,\n div,\n });\n\n // Render the Component which will trigger the LayerManager's useEffect\n flushSync(() => {\n root.render(<Component />);\n });\n }\n\n const container = this.containers.get(position);\n if (container && container.manager) {\n return container.manager.add(options);\n }\n\n // If manager is not ready yet, add to pending queue\n return new Promise<string>((resolve) => {\n const queue = this.pending.get(position) || [];\n queue.push((manager) => {\n resolve(manager.add(options));\n });\n this.pending.set(position, queue);\n });\n };\n\n /**\n * Removes a notification\n *\n * @param position - The position of the notification container\n * @param id - The unique ID of the notification to remove\n */\n public remove = (position: NOTIFICATION_POSITION, id: string) => {\n const container = this.containers.get(position);\n if (container && container.manager) {\n container.manager.remove(id);\n }\n };\n\n /**\n * Destroys entire stack of notifications at a position.\n * Unmounts the React root and cleans up DOM elements.\n *\n * @param position - The position of the notification container to destroy\n */\n public destroy = (position: NOTIFICATION_POSITION) => {\n const container = this.containers.get(position);\n if (container) {\n container.root.unmount();\n if (document.body.contains(container.div)) {\n document.body.removeChild(container.div);\n }\n this.containers.delete(position);\n }\n };\n}\n\n/** Export a singleton instance */\nexport default new Notification();\n"],"names":["positionMap","NOTIFICATION_POSITION","TOP_LEFT","LAYER_POSITION","TOP_RIGHT","BOTTOM_LEFT","BOTTOM_RIGHT","Notification","containers","Map","pending","add","position","options","ariaLabel","has","refCallback","instance","container","get","manager","queue","forEach","cb","delete","Component","LayerManager","renderLayer","closeOnEsc","closeOnOverlayClick","alwaysOnTop","component","_jsx","NotificationManager","ref","onEmpty","destroy","div","document","createElement","body","appendChild","root","createRoot","set","flushSync","render","Promise","resolve","push","remove","id","unmount","contains","removeChild"],"mappings":"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"}
@@ -200,6 +200,7 @@ const DEFAULT_DURATION$1 = 5000;
200
200
  */ this.pause = (id)=>()=>{
201
201
  if (id && this.timeouts[id]) {
202
202
  clearTimeout(this.timeouts[id]);
203
+ delete this.timeouts[id];
203
204
  }
204
205
  }, /**
205
206
  * Restart the removal of notification.