jvetrau-ds 0.2.2 → 0.2.4

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 (62) hide show
  1. package/components/avatar-upload/avatar-upload.cjs +1 -0
  2. package/components/avatar-upload/avatar-upload.cjs.map +1 -1
  3. package/components/avatar-upload/avatar-upload.js +1 -0
  4. package/components/avatar-upload/avatar-upload.js.map +1 -1
  5. package/components/button/button-presentation.cjs +17 -0
  6. package/components/button/button-presentation.cjs.map +1 -0
  7. package/components/button/button-presentation.d.ts +1 -0
  8. package/components/button/button-presentation.js +15 -0
  9. package/components/button/button-presentation.js.map +1 -0
  10. package/components/button/button.cjs +11 -18
  11. package/components/button/button.cjs.map +1 -1
  12. package/components/button/button.d.ts +4 -3
  13. package/components/button/button.js +12 -19
  14. package/components/button/button.js.map +1 -1
  15. package/components/button/index.cjs +11 -1
  16. package/components/button/index.d.ts +1 -0
  17. package/components/button/index.js +1 -0
  18. package/components/dropdown/dropdown.cjs +103 -26
  19. package/components/dropdown/dropdown.cjs.map +1 -1
  20. package/components/dropdown/dropdown.css +142 -0
  21. package/components/dropdown/dropdown.d.ts +2 -0
  22. package/components/dropdown/dropdown.js +103 -26
  23. package/components/dropdown/dropdown.js.map +1 -1
  24. package/components/flip-list/flip-list.cjs +5 -5
  25. package/components/flip-list/flip-list.cjs.map +1 -1
  26. package/components/flip-list/flip-list.css +20 -24
  27. package/components/flip-list/flip-list.js +4 -5
  28. package/components/flip-list/flip-list.js.map +1 -1
  29. package/components/index.cjs +5 -1
  30. package/components/index.d.ts +3 -2
  31. package/components/index.js +1 -1
  32. package/components/tag/tag.cjs +9 -4
  33. package/components/tag/tag.cjs.map +1 -1
  34. package/components/tag/tag.css +40 -27
  35. package/components/tag/tag.d.ts +2 -1
  36. package/components/tag/tag.js +9 -4
  37. package/components/tag/tag.js.map +1 -1
  38. package/components/video/video.cjs +5 -17
  39. package/components/video/video.cjs.map +1 -1
  40. package/components/video/video.js +5 -16
  41. package/components/video/video.js.map +1 -1
  42. package/icons/assets/close.cjs +14 -0
  43. package/icons/assets/close.cjs.map +1 -0
  44. package/icons/assets/close.d.ts +2 -0
  45. package/icons/assets/close.js +12 -0
  46. package/icons/assets/close.js.map +1 -0
  47. package/icons/manifest.cjs +6 -0
  48. package/icons/manifest.cjs.map +1 -1
  49. package/icons/manifest.d.ts +5 -0
  50. package/icons/manifest.js +6 -0
  51. package/icons/manifest.js.map +1 -1
  52. package/index.cjs +4 -0
  53. package/index.d.ts +2 -2
  54. package/index.js +1 -1
  55. package/package.json +1 -1
  56. package/patterns/header/header.cjs +36 -5
  57. package/patterns/header/header.cjs.map +1 -1
  58. package/patterns/header/header.css +45 -0
  59. package/patterns/header/header.d.ts +14 -2
  60. package/patterns/header/header.js +32 -5
  61. package/patterns/header/header.js.map +1 -1
  62. package/styles.css +246 -50
@@ -90,6 +90,7 @@ const AvatarUpload = ({
90
90
  {
91
91
  className: "avatar-upload__button",
92
92
  type: "button",
93
+ rank: "link",
93
94
  disabled: isDisabled,
94
95
  "aria-describedby": hasError ? errorId : void 0,
95
96
  onClick: handleSelectClick,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/avatar-upload/avatar-upload.tsx"],"names":["React","classnames","jsxs","jsx","Avatar","Button"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAM,eAEF,CAAC;AAAA,EACH,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,OAAA,GAAU,KAAA;AAAA,EACV,KAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,WACJA,sBAAA,CAAM,MAAA;AAAA,IACJ;AAAA,GACF;AAEF,EAAA,MAAM,OAAA,GAAUA,uBAAM,KAAA,EAAM;AAE5B,EAAA,MAAM,OAAA,GAAU,GAAG,OAAO,CAAA,MAAA,CAAA;AAE1B,EAAA,MAAM,QAAA,GACJ,KAAA,KAAU,IAAA,IACV,KAAA,KAAU,MAAA;AAEZ,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAUC,qBAAA;AAAA,IACd,eAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,yBAAA,EACE,UAAA;AAAA,MACF,wBAAA,EACE,OAAA;AAAA,MACF,sBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,IAAI,UAAA,EAAY;AACd,MAAA;AAAA,IACF;AAEA,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,MAAM,QAAQ,KAAA,CAAM,aAAA;AACpB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA;AAO5B,IAAA,KAAA,CAAM,KAAA,GAAQ,EAAA;AAEd,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAAA,EACnB,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAA,GACrB,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAErB,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,WAAA,EAAW,gBAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAAC,cAAA;AAAA,UAACC,uBAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,GAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,wBAEAD,cAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,sBAAA;AAAA,YACV,IAAA,EAAK,MAAA;AAAA,YACL,MAAA;AAAA,YACA,QAAA,EAAU,UAAA;AAAA,YACV,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEAA,cAAA;AAAA,UAACE,uBAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,IAAA,EAAK,QAAA;AAAA,YACL,QAAA,EAAU,UAAA;AAAA,YACV,kBAAA,EACE,WACI,OAAA,GACA,MAAA;AAAA,YAEN,OAAA,EAAS,iBAAA;AAAA,YAER,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,QAEC,QAAA,oBACCF,cAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,sBAAA;AAAA,YACV,EAAA,EAAI,OAAA;AAAA,YACJ,IAAA,EAAK,OAAA;AAAA,YAEJ,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,qBAAA,GAAQ","file":"avatar-upload.cjs","sourcesContent":["import React from 'react';\n\nimport './avatar-upload.css';\nimport Avatar from '../avatar/avatar';\nimport Button from '../button/button';\nimport { classnames } from '../helpers/classnames';\n\nexport interface AvatarUploadProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n > {\n src?: string;\n initials?: string;\n alt?: string;\n accept?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: React.ReactNode;\n selectLabel: React.ReactNode;\n onFileSelect: (file: File) => void;\n}\n\nconst AvatarUpload: React.FC<\n AvatarUploadProps\n> = ({\n src,\n initials,\n alt,\n accept,\n disabled = false,\n loading = false,\n error,\n selectLabel,\n onFileSelect,\n className = '',\n ...props\n}) => {\n const inputRef =\n React.useRef<HTMLInputElement>(\n null,\n );\n\n const reactId = React.useId();\n\n const errorId = `${reactId}-error`;\n\n const hasError =\n error !== null &&\n error !== undefined;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'avatar-upload',\n className,\n {\n 'avatar-upload--disabled':\n isDisabled,\n 'avatar-upload--loading':\n loading,\n 'avatar-upload--error':\n hasError,\n },\n );\n\n const handleSelectClick = () => {\n if (isDisabled) {\n return;\n }\n\n inputRef.current?.click();\n };\n\n const handleFileChange = (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n\n /*\n * Reset the native input after reading\n * the selected file so the same file\n * can be selected again later.\n */\n input.value = '';\n\n if (!file) {\n return;\n }\n\n onFileSelect(file);\n };\n\n const resolvedAriaBusy = loading\n ? true\n : props['aria-busy'];\n\n return (\n <div\n {...props}\n className={classes}\n aria-busy={resolvedAriaBusy}\n >\n <Avatar\n className=\"avatar-upload__avatar\"\n src={src}\n initials={initials}\n alt={alt}\n />\n\n <input\n ref={inputRef}\n className=\"avatar-upload__input\"\n type=\"file\"\n accept={accept}\n disabled={isDisabled}\n onChange={handleFileChange}\n />\n\n <Button\n className=\"avatar-upload__button\"\n type=\"button\"\n disabled={isDisabled}\n aria-describedby={\n hasError\n ? errorId\n : undefined\n }\n onClick={handleSelectClick}\n >\n {selectLabel}\n </Button>\n\n {hasError && (\n <div\n className=\"avatar-upload__error\"\n id={errorId}\n role=\"alert\"\n >\n {error}\n </div>\n )}\n </div>\n );\n};\n\nexport default AvatarUpload;"]}
1
+ {"version":3,"sources":["../../../src/components/avatar-upload/avatar-upload.tsx"],"names":["React","classnames","jsxs","jsx","Avatar","Button"],"mappings":"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","file":"avatar-upload.cjs","sourcesContent":["import React from 'react';\n\nimport './avatar-upload.css';\nimport Avatar from '../avatar/avatar';\nimport Button from '../button/button';\nimport { classnames } from '../helpers/classnames';\n\nexport interface AvatarUploadProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n > {\n src?: string;\n initials?: string;\n alt?: string;\n accept?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: React.ReactNode;\n selectLabel: React.ReactNode;\n onFileSelect: (file: File) => void;\n}\n\nconst AvatarUpload: React.FC<\n AvatarUploadProps\n> = ({\n src,\n initials,\n alt,\n accept,\n disabled = false,\n loading = false,\n error,\n selectLabel,\n onFileSelect,\n className = '',\n ...props\n}) => {\n const inputRef =\n React.useRef<HTMLInputElement>(\n null,\n );\n\n const reactId = React.useId();\n\n const errorId = `${reactId}-error`;\n\n const hasError =\n error !== null &&\n error !== undefined;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'avatar-upload',\n className,\n {\n 'avatar-upload--disabled':\n isDisabled,\n 'avatar-upload--loading':\n loading,\n 'avatar-upload--error':\n hasError,\n },\n );\n\n const handleSelectClick = () => {\n if (isDisabled) {\n return;\n }\n\n inputRef.current?.click();\n };\n\n const handleFileChange = (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n\n /*\n * Reset the native input after reading\n * the selected file so the same file\n * can be selected again later.\n */\n input.value = '';\n\n if (!file) {\n return;\n }\n\n onFileSelect(file);\n };\n\n const resolvedAriaBusy = loading\n ? true\n : props['aria-busy'];\n\n return (\n <div\n {...props}\n className={classes}\n aria-busy={resolvedAriaBusy}\n >\n <Avatar\n className=\"avatar-upload__avatar\"\n src={src}\n initials={initials}\n alt={alt}\n />\n\n <input\n ref={inputRef}\n className=\"avatar-upload__input\"\n type=\"file\"\n accept={accept}\n disabled={isDisabled}\n onChange={handleFileChange}\n />\n\n <Button\n className=\"avatar-upload__button\"\n type=\"button\"\n rank=\"link\"\n disabled={isDisabled}\n aria-describedby={\n hasError\n ? errorId\n : undefined\n }\n onClick={handleSelectClick}\n >\n {selectLabel}\n </Button>\n\n {hasError && (\n <div\n className=\"avatar-upload__error\"\n id={errorId}\n role=\"alert\"\n >\n {error}\n </div>\n )}\n </div>\n );\n};\n\nexport default AvatarUpload;\n"]}
@@ -82,6 +82,7 @@ const AvatarUpload = ({
82
82
  {
83
83
  className: "avatar-upload__button",
84
84
  type: "button",
85
+ rank: "link",
85
86
  disabled: isDisabled,
86
87
  "aria-describedby": hasError ? errorId : void 0,
87
88
  onClick: handleSelectClick,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/avatar-upload/avatar-upload.tsx"],"names":[],"mappings":";;;;;;;AAuBA,MAAM,eAEF,CAAC;AAAA,EACH,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,OAAA,GAAU,KAAA;AAAA,EACV,KAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,WACJ,KAAA,CAAM,MAAA;AAAA,IACJ;AAAA,GACF;AAEF,EAAA,MAAM,OAAA,GAAU,MAAM,KAAA,EAAM;AAE5B,EAAA,MAAM,OAAA,GAAU,GAAG,OAAO,CAAA,MAAA,CAAA;AAE1B,EAAA,MAAM,QAAA,GACJ,KAAA,KAAU,IAAA,IACV,KAAA,KAAU,MAAA;AAEZ,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,eAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,yBAAA,EACE,UAAA;AAAA,MACF,wBAAA,EACE,OAAA;AAAA,MACF,sBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,IAAI,UAAA,EAAY;AACd,MAAA;AAAA,IACF;AAEA,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,MAAM,QAAQ,KAAA,CAAM,aAAA;AACpB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA;AAO5B,IAAA,KAAA,CAAM,KAAA,GAAQ,EAAA;AAEd,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAAA,EACnB,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAA,GACrB,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAErB,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,WAAA,EAAW,gBAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,GAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,wBAEA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,sBAAA;AAAA,YACV,IAAA,EAAK,MAAA;AAAA,YACL,MAAA;AAAA,YACA,QAAA,EAAU,UAAA;AAAA,YACV,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,IAAA,EAAK,QAAA;AAAA,YACL,QAAA,EAAU,UAAA;AAAA,YACV,kBAAA,EACE,WACI,OAAA,GACA,MAAA;AAAA,YAEN,OAAA,EAAS,iBAAA;AAAA,YAER,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,QAEC,QAAA,oBACC,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,sBAAA;AAAA,YACV,EAAA,EAAI,OAAA;AAAA,YACJ,IAAA,EAAK,OAAA;AAAA,YAEJ,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,qBAAA,GAAQ","file":"avatar-upload.js","sourcesContent":["import React from 'react';\n\nimport './avatar-upload.css';\nimport Avatar from '../avatar/avatar';\nimport Button from '../button/button';\nimport { classnames } from '../helpers/classnames';\n\nexport interface AvatarUploadProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n > {\n src?: string;\n initials?: string;\n alt?: string;\n accept?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: React.ReactNode;\n selectLabel: React.ReactNode;\n onFileSelect: (file: File) => void;\n}\n\nconst AvatarUpload: React.FC<\n AvatarUploadProps\n> = ({\n src,\n initials,\n alt,\n accept,\n disabled = false,\n loading = false,\n error,\n selectLabel,\n onFileSelect,\n className = '',\n ...props\n}) => {\n const inputRef =\n React.useRef<HTMLInputElement>(\n null,\n );\n\n const reactId = React.useId();\n\n const errorId = `${reactId}-error`;\n\n const hasError =\n error !== null &&\n error !== undefined;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'avatar-upload',\n className,\n {\n 'avatar-upload--disabled':\n isDisabled,\n 'avatar-upload--loading':\n loading,\n 'avatar-upload--error':\n hasError,\n },\n );\n\n const handleSelectClick = () => {\n if (isDisabled) {\n return;\n }\n\n inputRef.current?.click();\n };\n\n const handleFileChange = (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n\n /*\n * Reset the native input after reading\n * the selected file so the same file\n * can be selected again later.\n */\n input.value = '';\n\n if (!file) {\n return;\n }\n\n onFileSelect(file);\n };\n\n const resolvedAriaBusy = loading\n ? true\n : props['aria-busy'];\n\n return (\n <div\n {...props}\n className={classes}\n aria-busy={resolvedAriaBusy}\n >\n <Avatar\n className=\"avatar-upload__avatar\"\n src={src}\n initials={initials}\n alt={alt}\n />\n\n <input\n ref={inputRef}\n className=\"avatar-upload__input\"\n type=\"file\"\n accept={accept}\n disabled={isDisabled}\n onChange={handleFileChange}\n />\n\n <Button\n className=\"avatar-upload__button\"\n type=\"button\"\n disabled={isDisabled}\n aria-describedby={\n hasError\n ? errorId\n : undefined\n }\n onClick={handleSelectClick}\n >\n {selectLabel}\n </Button>\n\n {hasError && (\n <div\n className=\"avatar-upload__error\"\n id={errorId}\n role=\"alert\"\n >\n {error}\n </div>\n )}\n </div>\n );\n};\n\nexport default AvatarUpload;"]}
1
+ {"version":3,"sources":["../../../src/components/avatar-upload/avatar-upload.tsx"],"names":[],"mappings":";;;;;;;AAuBA,MAAM,eAEF,CAAC;AAAA,EACH,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,OAAA,GAAU,KAAA;AAAA,EACV,KAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,WACJ,KAAA,CAAM,MAAA;AAAA,IACJ;AAAA,GACF;AAEF,EAAA,MAAM,OAAA,GAAU,MAAM,KAAA,EAAM;AAE5B,EAAA,MAAM,OAAA,GAAU,GAAG,OAAO,CAAA,MAAA,CAAA;AAE1B,EAAA,MAAM,QAAA,GACJ,KAAA,KAAU,IAAA,IACV,KAAA,KAAU,MAAA;AAEZ,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,eAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,yBAAA,EACE,UAAA;AAAA,MACF,wBAAA,EACE,OAAA;AAAA,MACF,sBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,IAAI,UAAA,EAAY;AACd,MAAA;AAAA,IACF;AAEA,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,MAAM,QAAQ,KAAA,CAAM,aAAA;AACpB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA;AAO5B,IAAA,KAAA,CAAM,KAAA,GAAQ,EAAA;AAEd,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAAA,EACnB,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAA,GACrB,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAErB,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,WAAA,EAAW,gBAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,GAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,wBAEA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,sBAAA;AAAA,YACV,IAAA,EAAK,MAAA;AAAA,YACL,MAAA;AAAA,YACA,QAAA,EAAU,UAAA;AAAA,YACV,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,uBAAA;AAAA,YACV,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,MAAA;AAAA,YACL,QAAA,EAAU,UAAA;AAAA,YACV,kBAAA,EACE,WACI,OAAA,GACA,MAAA;AAAA,YAEN,OAAA,EAAS,iBAAA;AAAA,YAER,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,QAEC,QAAA,oBACC,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,sBAAA;AAAA,YACV,EAAA,EAAI,OAAA;AAAA,YACJ,IAAA,EAAK,OAAA;AAAA,YAEJ,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,qBAAA,GAAQ","file":"avatar-upload.js","sourcesContent":["import React from 'react';\n\nimport './avatar-upload.css';\nimport Avatar from '../avatar/avatar';\nimport Button from '../button/button';\nimport { classnames } from '../helpers/classnames';\n\nexport interface AvatarUploadProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children'\n > {\n src?: string;\n initials?: string;\n alt?: string;\n accept?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: React.ReactNode;\n selectLabel: React.ReactNode;\n onFileSelect: (file: File) => void;\n}\n\nconst AvatarUpload: React.FC<\n AvatarUploadProps\n> = ({\n src,\n initials,\n alt,\n accept,\n disabled = false,\n loading = false,\n error,\n selectLabel,\n onFileSelect,\n className = '',\n ...props\n}) => {\n const inputRef =\n React.useRef<HTMLInputElement>(\n null,\n );\n\n const reactId = React.useId();\n\n const errorId = `${reactId}-error`;\n\n const hasError =\n error !== null &&\n error !== undefined;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'avatar-upload',\n className,\n {\n 'avatar-upload--disabled':\n isDisabled,\n 'avatar-upload--loading':\n loading,\n 'avatar-upload--error':\n hasError,\n },\n );\n\n const handleSelectClick = () => {\n if (isDisabled) {\n return;\n }\n\n inputRef.current?.click();\n };\n\n const handleFileChange = (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const input = event.currentTarget;\n const file = input.files?.[0];\n\n /*\n * Reset the native input after reading\n * the selected file so the same file\n * can be selected again later.\n */\n input.value = '';\n\n if (!file) {\n return;\n }\n\n onFileSelect(file);\n };\n\n const resolvedAriaBusy = loading\n ? true\n : props['aria-busy'];\n\n return (\n <div\n {...props}\n className={classes}\n aria-busy={resolvedAriaBusy}\n >\n <Avatar\n className=\"avatar-upload__avatar\"\n src={src}\n initials={initials}\n alt={alt}\n />\n\n <input\n ref={inputRef}\n className=\"avatar-upload__input\"\n type=\"file\"\n accept={accept}\n disabled={isDisabled}\n onChange={handleFileChange}\n />\n\n <Button\n className=\"avatar-upload__button\"\n type=\"button\"\n rank=\"link\"\n disabled={isDisabled}\n aria-describedby={\n hasError\n ? errorId\n : undefined\n }\n onClick={handleSelectClick}\n >\n {selectLabel}\n </Button>\n\n {hasError && (\n <div\n className=\"avatar-upload__error\"\n id={errorId}\n role=\"alert\"\n >\n {error}\n </div>\n )}\n </div>\n );\n};\n\nexport default AvatarUpload;\n"]}
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var classnames = require('../helpers/classnames');
4
+
5
+ function buttonLink(className = "") {
6
+ return classnames.classnames(
7
+ "button",
8
+ className,
9
+ {
10
+ "button--link": true
11
+ }
12
+ );
13
+ }
14
+
15
+ exports.buttonLink = buttonLink;
16
+ //# sourceMappingURL=button-presentation.cjs.map
17
+ //# sourceMappingURL=button-presentation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/button/button-presentation.ts"],"names":["classnames"],"mappings":";;;;AAEO,SAAS,UAAA,CACd,YAAY,EAAA,EACJ;AACR,EAAA,OAAOA,qBAAA;AAAA,IACL,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,cAAA,EAAgB;AAAA;AAClB,GACF;AACF","file":"button-presentation.cjs","sourcesContent":["import { classnames } from '../helpers/classnames';\n\nexport function buttonLink(\n className = '',\n): string {\n return classnames(\n 'button',\n className,\n {\n 'button--link': true,\n },\n );\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function buttonLink(className?: string): string;
@@ -0,0 +1,15 @@
1
+ import { classnames } from '../helpers/classnames';
2
+
3
+ function buttonLink(className = "") {
4
+ return classnames(
5
+ "button",
6
+ className,
7
+ {
8
+ "button--link": true
9
+ }
10
+ );
11
+ }
12
+
13
+ export { buttonLink };
14
+ //# sourceMappingURL=button-presentation.js.map
15
+ //# sourceMappingURL=button-presentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/button/button-presentation.ts"],"names":[],"mappings":";;AAEO,SAAS,UAAA,CACd,YAAY,EAAA,EACJ;AACR,EAAA,OAAO,UAAA;AAAA,IACL,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,cAAA,EAAgB;AAAA;AAClB,GACF;AACF","file":"button-presentation.js","sourcesContent":["import { classnames } from '../helpers/classnames';\n\nexport function buttonLink(\n className = '',\n): string {\n return classnames(\n 'button',\n className,\n {\n 'button--link': true,\n },\n );\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
4
  require('./button.css');
6
5
  var Icon = require('../../icons/icon');
7
6
  var classnames = require('../helpers/classnames');
@@ -24,7 +23,7 @@ const Button = ({
24
23
  children,
25
24
  ...props
26
25
  }) => {
27
- const hasIcon = hasContent(icon);
26
+ const hasIcon = icon !== void 0;
28
27
  const hasChildren = hasContent(children);
29
28
  const isIconOnly = hasIcon && !hasChildren;
30
29
  const isDisabled = disabled || loading;
@@ -41,22 +40,16 @@ const Button = ({
41
40
  "button--icon-only": isIconOnly
42
41
  }
43
42
  );
44
- let resolvedIcon = icon;
45
- if (react.isValidElement(icon) && icon.type === Icon__default.default) {
46
- const iconElement = icon;
47
- resolvedIcon = react.cloneElement(
48
- iconElement,
49
- {
50
- size: iconElement.props.size ?? "base",
51
- className: classnames.classnames(
52
- "button__icon",
53
- iconElement.props.className
54
- ),
55
- "aria-hidden": iconElement.props["aria-hidden"] ?? true,
56
- focusable: iconElement.props.focusable ?? false
57
- }
58
- );
59
- }
43
+ const resolvedIcon = hasIcon ? /* @__PURE__ */ jsxRuntime.jsx(
44
+ Icon__default.default,
45
+ {
46
+ name: icon,
47
+ size: "base",
48
+ className: "button__icon",
49
+ "aria-hidden": true,
50
+ focusable: false
51
+ }
52
+ ) : null;
60
53
  const resolvedAriaBusy = loading ? true : props["aria-busy"];
61
54
  return /* @__PURE__ */ jsxRuntime.jsxs(
62
55
  "button",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/button/button.tsx"],"names":["classnames","isValidElement","Icon","cloneElement","jsxs"],"mappings":";;;;;;;;;;;;AA6DA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,IAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,WAAW,IAAI,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,WAAW,QAAQ,CAAA;AAEvC,EAAA,MAAM,UAAA,GACJ,WAAW,CAAC,WAAA;AAEd,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAUA,qBAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,gBACE,IAAA,KAAS,MAAA;AAAA,MACX,mBACE,OAAA,KAAY,SAAA;AAAA,MACd,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,kBAAA,EACE,UAAA;AAAA,MACF,iBAAA,EACE,OAAA;AAAA,MACF,mBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,EAAA,IACEC,oBAAA,CAAe,IAAI,CAAA,IACnB,IAAA,CAAK,SAASC,qBAAA,EACd;AACA,IAAA,MAAM,WAAA,GACJ,IAAA;AAEF,IAAA,YAAA,GAAeC,kBAAA;AAAA,MACb,WAAA;AAAA,MACA;AAAA,QACE,IAAA,EACE,WAAA,CAAY,KAAA,CAAM,IAAA,IAClB,MAAA;AAAA,QACF,SAAA,EAAWH,qBAAA;AAAA,UACT,cAAA;AAAA,UACA,YAAY,KAAA,CAAM;AAAA,SACpB;AAAA,QACA,aAAA,EACE,WAAA,CAAY,KAAA,CACV,aACF,CAAA,IAAK,IAAA;AAAA,QACP,SAAA,EACE,WAAA,CAAY,KAAA,CACT,SAAA,IAAa;AAAA;AACpB,KACF;AAAA,EACF;AAEA,EAAA,MAAM,gBAAA,GACJ,OAAA,GACI,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAEvB,EAAA,uBACEI,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,UAAA;AAAA,MACV,WAAA,EAAW,gBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,QAAA,YAAA;AAAA,QACA;AAAA;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"button.cjs","sourcesContent":["import React, {\n cloneElement,\n isValidElement,\n type ReactElement,\n} from 'react';\n\nimport './button.css';\nimport Icon, { type IconProps } from '../../icons/icon';\nimport { classnames } from '../helpers/classnames';\n\nexport type ButtonRank =\n | 'default'\n | 'primary'\n | 'link';\n\nexport type ButtonDensity =\n | 'default'\n | 'compact';\n\ntype ButtonNativeProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'children'\n>;\n\ninterface ButtonSharedProps\n extends ButtonNativeProps {\n density?: ButtonDensity;\n loading?: boolean;\n}\n\ntype RegularButtonContentProps =\n | {\n children: React.ReactNode;\n icon?: React.ReactNode;\n }\n | {\n children?: never;\n icon: React.ReactNode;\n 'aria-label': string;\n };\n\ntype RegularButtonProps =\n ButtonSharedProps &\n RegularButtonContentProps & {\n mode?: 'default';\n rank?: ButtonRank;\n };\n\ntype ToolbarButtonProps =\n ButtonSharedProps & {\n mode: 'toolbar';\n icon: React.ReactNode;\n children?: never;\n rank?: never;\n 'aria-label': string;\n };\n\nexport type ButtonProps =\n | RegularButtonProps\n | ToolbarButtonProps;\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return value !== null && value !== undefined;\n}\n\nconst Button: React.FC<ButtonProps> = ({\n mode = 'default',\n rank = 'default',\n density = 'default',\n loading = false,\n icon,\n className = '',\n disabled = false,\n children,\n ...props\n}) => {\n const hasIcon = hasContent(icon);\n const hasChildren = hasContent(children);\n\n const isIconOnly =\n hasIcon && !hasChildren;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'button',\n className,\n {\n 'button--primary':\n rank === 'primary',\n 'button--link':\n rank === 'link',\n 'button--compact':\n density === 'compact',\n 'button--toolbar':\n mode === 'toolbar',\n 'button--disabled':\n isDisabled,\n 'button--loading':\n loading,\n 'button--icon-only':\n isIconOnly,\n },\n );\n\n let resolvedIcon = icon;\n\n if (\n isValidElement(icon) &&\n icon.type === Icon\n ) {\n const iconElement =\n icon as ReactElement<IconProps>;\n\n resolvedIcon = cloneElement(\n iconElement,\n {\n size:\n iconElement.props.size ??\n 'base',\n className: classnames(\n 'button__icon',\n iconElement.props.className,\n ),\n 'aria-hidden':\n iconElement.props[\n 'aria-hidden'\n ] ?? true,\n focusable:\n iconElement.props\n .focusable ?? false,\n },\n );\n }\n\n const resolvedAriaBusy =\n loading\n ? true\n : props['aria-busy'];\n\n return (\n <button\n {...props}\n className={classes}\n disabled={isDisabled}\n aria-busy={resolvedAriaBusy}\n >\n {resolvedIcon}\n {children}\n </button>\n );\n};\n\nexport default Button;\n"]}
1
+ {"version":3,"sources":["../../../src/components/button/button.tsx"],"names":["classnames","jsx","Icon","jsxs"],"mappings":";;;;;;;;;;;AA0DA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,IAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,UAAU,IAAA,KAAS,MAAA;AACzB,EAAA,MAAM,WAAA,GAAc,WAAW,QAAQ,CAAA;AAEvC,EAAA,MAAM,UAAA,GACJ,WAAW,CAAC,WAAA;AAEd,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAUA,qBAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,gBACE,IAAA,KAAS,MAAA;AAAA,MACX,mBACE,OAAA,KAAY,SAAA;AAAA,MACd,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,kBAAA,EACE,UAAA;AAAA,MACF,iBAAA,EACE,OAAA;AAAA,MACF,mBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,eAAe,OAAA,mBACnBC,cAAA;AAAA,IAACC,qBAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,IAAA;AAAA,MACN,IAAA,EAAK,MAAA;AAAA,MACL,SAAA,EAAU,cAAA;AAAA,MACV,aAAA,EAAW,IAAA;AAAA,MACX,SAAA,EAAW;AAAA;AAAA,GACb,GACE,IAAA;AAEJ,EAAA,MAAM,gBAAA,GACJ,OAAA,GACI,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAEvB,EAAA,uBACEC,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,UAAA;AAAA,MACV,WAAA,EAAW,gBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,QAAA,YAAA;AAAA,QACA;AAAA;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"button.cjs","sourcesContent":["import React from 'react';\n\nimport './button.css';\nimport Icon from '../../icons/icon';\nimport type { IconName } from '../../icons/types';\nimport { classnames } from '../helpers/classnames';\n\nexport type ButtonRank =\n | 'default'\n | 'primary'\n | 'link';\n\nexport type ButtonDensity =\n | 'default'\n | 'compact';\n\ntype ButtonNativeProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'children'\n>;\n\ninterface ButtonSharedProps\n extends ButtonNativeProps {\n density?: ButtonDensity;\n loading?: boolean;\n}\n\ntype RegularButtonContentProps =\n | {\n children: React.ReactNode;\n icon?: IconName;\n }\n | {\n children?: never;\n icon: IconName;\n 'aria-label': string;\n };\n\ntype RegularButtonProps =\n ButtonSharedProps &\n RegularButtonContentProps & {\n mode?: 'default';\n rank?: ButtonRank;\n };\n\ntype ToolbarButtonProps =\n ButtonSharedProps & {\n mode: 'toolbar';\n icon: IconName;\n children?: never;\n rank?: never;\n 'aria-label': string;\n };\n\nexport type ButtonProps =\n | RegularButtonProps\n | ToolbarButtonProps;\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return value !== null && value !== undefined;\n}\n\nconst Button: React.FC<ButtonProps> = ({\n mode = 'default',\n rank = 'default',\n density = 'default',\n loading = false,\n icon,\n className = '',\n disabled = false,\n children,\n ...props\n}) => {\n const hasIcon = icon !== undefined;\n const hasChildren = hasContent(children);\n\n const isIconOnly =\n hasIcon && !hasChildren;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'button',\n className,\n {\n 'button--primary':\n rank === 'primary',\n 'button--link':\n rank === 'link',\n 'button--compact':\n density === 'compact',\n 'button--toolbar':\n mode === 'toolbar',\n 'button--disabled':\n isDisabled,\n 'button--loading':\n loading,\n 'button--icon-only':\n isIconOnly,\n },\n );\n\n const resolvedIcon = hasIcon ? (\n <Icon\n name={icon}\n size=\"base\"\n className=\"button__icon\"\n aria-hidden\n focusable={false}\n />\n ) : null;\n\n const resolvedAriaBusy =\n loading\n ? true\n : props['aria-busy'];\n\n return (\n <button\n {...props}\n className={classes}\n disabled={isDisabled}\n aria-busy={resolvedAriaBusy}\n >\n {resolvedIcon}\n {children}\n </button>\n );\n};\n\nexport default Button;\n"]}
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import './button.css';
3
+ import type { IconName } from '../../icons/types';
3
4
  export type ButtonRank = 'default' | 'primary' | 'link';
4
5
  export type ButtonDensity = 'default' | 'compact';
5
6
  type ButtonNativeProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'>;
@@ -9,10 +10,10 @@ interface ButtonSharedProps extends ButtonNativeProps {
9
10
  }
10
11
  type RegularButtonContentProps = {
11
12
  children: React.ReactNode;
12
- icon?: React.ReactNode;
13
+ icon?: IconName;
13
14
  } | {
14
15
  children?: never;
15
- icon: React.ReactNode;
16
+ icon: IconName;
16
17
  'aria-label': string;
17
18
  };
18
19
  type RegularButtonProps = ButtonSharedProps & RegularButtonContentProps & {
@@ -21,7 +22,7 @@ type RegularButtonProps = ButtonSharedProps & RegularButtonContentProps & {
21
22
  };
22
23
  type ToolbarButtonProps = ButtonSharedProps & {
23
24
  mode: 'toolbar';
24
- icon: React.ReactNode;
25
+ icon: IconName;
25
26
  children?: never;
26
27
  rank?: never;
27
28
  'aria-label': string;
@@ -1,5 +1,4 @@
1
- import { jsxs } from 'react/jsx-runtime';
2
- import { isValidElement, cloneElement } from 'react';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
2
  import './button.css';
4
3
  import Icon from '../../icons/icon';
5
4
  import { classnames } from '../helpers/classnames';
@@ -18,7 +17,7 @@ const Button = ({
18
17
  children,
19
18
  ...props
20
19
  }) => {
21
- const hasIcon = hasContent(icon);
20
+ const hasIcon = icon !== void 0;
22
21
  const hasChildren = hasContent(children);
23
22
  const isIconOnly = hasIcon && !hasChildren;
24
23
  const isDisabled = disabled || loading;
@@ -35,22 +34,16 @@ const Button = ({
35
34
  "button--icon-only": isIconOnly
36
35
  }
37
36
  );
38
- let resolvedIcon = icon;
39
- if (isValidElement(icon) && icon.type === Icon) {
40
- const iconElement = icon;
41
- resolvedIcon = cloneElement(
42
- iconElement,
43
- {
44
- size: iconElement.props.size ?? "base",
45
- className: classnames(
46
- "button__icon",
47
- iconElement.props.className
48
- ),
49
- "aria-hidden": iconElement.props["aria-hidden"] ?? true,
50
- focusable: iconElement.props.focusable ?? false
51
- }
52
- );
53
- }
37
+ const resolvedIcon = hasIcon ? /* @__PURE__ */ jsx(
38
+ Icon,
39
+ {
40
+ name: icon,
41
+ size: "base",
42
+ className: "button__icon",
43
+ "aria-hidden": true,
44
+ focusable: false
45
+ }
46
+ ) : null;
54
47
  const resolvedAriaBusy = loading ? true : props["aria-busy"];
55
48
  return /* @__PURE__ */ jsxs(
56
49
  "button",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/button/button.tsx"],"names":[],"mappings":";;;;;;AA6DA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,IAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,WAAW,IAAI,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,WAAW,QAAQ,CAAA;AAEvC,EAAA,MAAM,UAAA,GACJ,WAAW,CAAC,WAAA;AAEd,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,gBACE,IAAA,KAAS,MAAA;AAAA,MACX,mBACE,OAAA,KAAY,SAAA;AAAA,MACd,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,kBAAA,EACE,UAAA;AAAA,MACF,iBAAA,EACE,OAAA;AAAA,MACF,mBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,EAAA,IACE,cAAA,CAAe,IAAI,CAAA,IACnB,IAAA,CAAK,SAAS,IAAA,EACd;AACA,IAAA,MAAM,WAAA,GACJ,IAAA;AAEF,IAAA,YAAA,GAAe,YAAA;AAAA,MACb,WAAA;AAAA,MACA;AAAA,QACE,IAAA,EACE,WAAA,CAAY,KAAA,CAAM,IAAA,IAClB,MAAA;AAAA,QACF,SAAA,EAAW,UAAA;AAAA,UACT,cAAA;AAAA,UACA,YAAY,KAAA,CAAM;AAAA,SACpB;AAAA,QACA,aAAA,EACE,WAAA,CAAY,KAAA,CACV,aACF,CAAA,IAAK,IAAA;AAAA,QACP,SAAA,EACE,WAAA,CAAY,KAAA,CACT,SAAA,IAAa;AAAA;AACpB,KACF;AAAA,EACF;AAEA,EAAA,MAAM,gBAAA,GACJ,OAAA,GACI,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAEvB,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,UAAA;AAAA,MACV,WAAA,EAAW,gBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,QAAA,YAAA;AAAA,QACA;AAAA;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"button.js","sourcesContent":["import React, {\n cloneElement,\n isValidElement,\n type ReactElement,\n} from 'react';\n\nimport './button.css';\nimport Icon, { type IconProps } from '../../icons/icon';\nimport { classnames } from '../helpers/classnames';\n\nexport type ButtonRank =\n | 'default'\n | 'primary'\n | 'link';\n\nexport type ButtonDensity =\n | 'default'\n | 'compact';\n\ntype ButtonNativeProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'children'\n>;\n\ninterface ButtonSharedProps\n extends ButtonNativeProps {\n density?: ButtonDensity;\n loading?: boolean;\n}\n\ntype RegularButtonContentProps =\n | {\n children: React.ReactNode;\n icon?: React.ReactNode;\n }\n | {\n children?: never;\n icon: React.ReactNode;\n 'aria-label': string;\n };\n\ntype RegularButtonProps =\n ButtonSharedProps &\n RegularButtonContentProps & {\n mode?: 'default';\n rank?: ButtonRank;\n };\n\ntype ToolbarButtonProps =\n ButtonSharedProps & {\n mode: 'toolbar';\n icon: React.ReactNode;\n children?: never;\n rank?: never;\n 'aria-label': string;\n };\n\nexport type ButtonProps =\n | RegularButtonProps\n | ToolbarButtonProps;\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return value !== null && value !== undefined;\n}\n\nconst Button: React.FC<ButtonProps> = ({\n mode = 'default',\n rank = 'default',\n density = 'default',\n loading = false,\n icon,\n className = '',\n disabled = false,\n children,\n ...props\n}) => {\n const hasIcon = hasContent(icon);\n const hasChildren = hasContent(children);\n\n const isIconOnly =\n hasIcon && !hasChildren;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'button',\n className,\n {\n 'button--primary':\n rank === 'primary',\n 'button--link':\n rank === 'link',\n 'button--compact':\n density === 'compact',\n 'button--toolbar':\n mode === 'toolbar',\n 'button--disabled':\n isDisabled,\n 'button--loading':\n loading,\n 'button--icon-only':\n isIconOnly,\n },\n );\n\n let resolvedIcon = icon;\n\n if (\n isValidElement(icon) &&\n icon.type === Icon\n ) {\n const iconElement =\n icon as ReactElement<IconProps>;\n\n resolvedIcon = cloneElement(\n iconElement,\n {\n size:\n iconElement.props.size ??\n 'base',\n className: classnames(\n 'button__icon',\n iconElement.props.className,\n ),\n 'aria-hidden':\n iconElement.props[\n 'aria-hidden'\n ] ?? true,\n focusable:\n iconElement.props\n .focusable ?? false,\n },\n );\n }\n\n const resolvedAriaBusy =\n loading\n ? true\n : props['aria-busy'];\n\n return (\n <button\n {...props}\n className={classes}\n disabled={isDisabled}\n aria-busy={resolvedAriaBusy}\n >\n {resolvedIcon}\n {children}\n </button>\n );\n};\n\nexport default Button;\n"]}
1
+ {"version":3,"sources":["../../../src/components/button/button.tsx"],"names":[],"mappings":";;;;;AA0DA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,OAAA,GAAU,SAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,IAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,UAAU,IAAA,KAAS,MAAA;AACzB,EAAA,MAAM,WAAA,GAAc,WAAW,QAAQ,CAAA;AAEvC,EAAA,MAAM,UAAA,GACJ,WAAW,CAAC,WAAA;AAEd,EAAA,MAAM,aACJ,QAAA,IAAY,OAAA;AAEd,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,gBACE,IAAA,KAAS,MAAA;AAAA,MACX,mBACE,OAAA,KAAY,SAAA;AAAA,MACd,mBACE,IAAA,KAAS,SAAA;AAAA,MACX,kBAAA,EACE,UAAA;AAAA,MACF,iBAAA,EACE,OAAA;AAAA,MACF,mBAAA,EACE;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,eAAe,OAAA,mBACnB,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,IAAA;AAAA,MACN,IAAA,EAAK,MAAA;AAAA,MACL,SAAA,EAAU,cAAA;AAAA,MACV,aAAA,EAAW,IAAA;AAAA,MACX,SAAA,EAAW;AAAA;AAAA,GACb,GACE,IAAA;AAEJ,EAAA,MAAM,gBAAA,GACJ,OAAA,GACI,IAAA,GACA,KAAA,CAAM,WAAW,CAAA;AAEvB,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,UAAA;AAAA,MACV,WAAA,EAAW,gBAAA;AAAA,MAEV,QAAA,EAAA;AAAA,QAAA,YAAA;AAAA,QACA;AAAA;AAAA;AAAA,GACH;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"button.js","sourcesContent":["import React from 'react';\n\nimport './button.css';\nimport Icon from '../../icons/icon';\nimport type { IconName } from '../../icons/types';\nimport { classnames } from '../helpers/classnames';\n\nexport type ButtonRank =\n | 'default'\n | 'primary'\n | 'link';\n\nexport type ButtonDensity =\n | 'default'\n | 'compact';\n\ntype ButtonNativeProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'children'\n>;\n\ninterface ButtonSharedProps\n extends ButtonNativeProps {\n density?: ButtonDensity;\n loading?: boolean;\n}\n\ntype RegularButtonContentProps =\n | {\n children: React.ReactNode;\n icon?: IconName;\n }\n | {\n children?: never;\n icon: IconName;\n 'aria-label': string;\n };\n\ntype RegularButtonProps =\n ButtonSharedProps &\n RegularButtonContentProps & {\n mode?: 'default';\n rank?: ButtonRank;\n };\n\ntype ToolbarButtonProps =\n ButtonSharedProps & {\n mode: 'toolbar';\n icon: IconName;\n children?: never;\n rank?: never;\n 'aria-label': string;\n };\n\nexport type ButtonProps =\n | RegularButtonProps\n | ToolbarButtonProps;\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return value !== null && value !== undefined;\n}\n\nconst Button: React.FC<ButtonProps> = ({\n mode = 'default',\n rank = 'default',\n density = 'default',\n loading = false,\n icon,\n className = '',\n disabled = false,\n children,\n ...props\n}) => {\n const hasIcon = icon !== undefined;\n const hasChildren = hasContent(children);\n\n const isIconOnly =\n hasIcon && !hasChildren;\n\n const isDisabled =\n disabled || loading;\n\n const classes = classnames(\n 'button',\n className,\n {\n 'button--primary':\n rank === 'primary',\n 'button--link':\n rank === 'link',\n 'button--compact':\n density === 'compact',\n 'button--toolbar':\n mode === 'toolbar',\n 'button--disabled':\n isDisabled,\n 'button--loading':\n loading,\n 'button--icon-only':\n isIconOnly,\n },\n );\n\n const resolvedIcon = hasIcon ? (\n <Icon\n name={icon}\n size=\"base\"\n className=\"button__icon\"\n aria-hidden\n focusable={false}\n />\n ) : null;\n\n const resolvedAriaBusy =\n loading\n ? true\n : props['aria-busy'];\n\n return (\n <button\n {...props}\n className={classes}\n disabled={isDisabled}\n aria-busy={resolvedAriaBusy}\n >\n {resolvedIcon}\n {children}\n </button>\n );\n};\n\nexport default Button;\n"]}
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  var button = require('./button');
6
+ var buttonPresentation = require('./button-presentation');
4
7
 
5
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
9
 
@@ -8,6 +11,13 @@ var button__default = /*#__PURE__*/_interopDefault(button);
8
11
 
9
12
 
10
13
 
11
- module.exports = button__default.default;
14
+ Object.defineProperty(exports, "default", {
15
+ enumerable: true,
16
+ get: function () { return button__default.default; }
17
+ });
18
+ Object.defineProperty(exports, "buttonLink", {
19
+ enumerable: true,
20
+ get: function () { return buttonPresentation.buttonLink; }
21
+ });
12
22
  //# sourceMappingURL=index.cjs.map
13
23
  //# sourceMappingURL=index.cjs.map
@@ -1,2 +1,3 @@
1
1
  export { default } from './button';
2
2
  export type { ButtonProps } from './button';
3
+ export { buttonLink } from './button-presentation';
@@ -1,3 +1,4 @@
1
1
  export { default } from './button';
2
+ export { buttonLink } from './button-presentation';
2
3
  //# sourceMappingURL=index.js.map
3
4
  //# sourceMappingURL=index.js.map
@@ -11,36 +11,59 @@ const Dropdown = ({
11
11
  defaultValue,
12
12
  label = "Dropdown",
13
13
  align = "bottom-start",
14
+ interaction = "click",
14
15
  trigger,
15
16
  onChange,
16
17
  className = "",
18
+ onMouseEnter,
19
+ onMouseLeave,
20
+ onFocus,
21
+ onBlur,
17
22
  ...props
18
23
  }) => {
19
24
  const dropdownRef = react.useRef(null);
20
25
  const [isOpen, setIsOpen] = react.useState(false);
21
- const [internalValue, setInternalValue] = react.useState(defaultValue);
26
+ const [
27
+ internalValue,
28
+ setInternalValue
29
+ ] = react.useState(defaultValue);
22
30
  const selectedValue = value ?? internalValue;
23
- const classes = classnames.classnames("dropdown", className, {
24
- "dropdown--open": isOpen,
25
- "dropdown--top-start": align === "top-start",
26
- "dropdown--top-end": align === "top-end",
27
- "dropdown--bottom-start": align === "bottom-start",
28
- "dropdown--bottom-end": align === "bottom-end"
29
- });
31
+ const isHoverInteraction = interaction === "hover";
32
+ const classes = classnames.classnames(
33
+ "dropdown",
34
+ className,
35
+ {
36
+ "dropdown--open": isOpen,
37
+ "dropdown--top-start": align === "top-start",
38
+ "dropdown--top-end": align === "top-end",
39
+ "dropdown--bottom-start": align === "bottom-start",
40
+ "dropdown--bottom-end": align === "bottom-end"
41
+ }
42
+ );
30
43
  const triggerElement = trigger;
31
44
  const triggerClasses = classnames.classnames(
32
45
  "dropdown__trigger",
33
46
  triggerElement.props.className
34
47
  );
35
- const resolvedTrigger = react.cloneElement(triggerElement, {
36
- className: triggerClasses,
37
- "aria-haspopup": "menu",
38
- "aria-expanded": isOpen,
39
- onClick: (event) => {
40
- triggerElement.props.onClick?.(event);
41
- setIsOpen((currentValue) => !currentValue);
48
+ const resolvedTrigger = react.cloneElement(
49
+ triggerElement,
50
+ {
51
+ className: triggerClasses,
52
+ "aria-haspopup": "menu",
53
+ "aria-expanded": isOpen,
54
+ onClick: (event) => {
55
+ triggerElement.props.onClick?.(
56
+ event
57
+ );
58
+ if (isHoverInteraction) {
59
+ return;
60
+ }
61
+ setIsOpen(
62
+ (currentValue) => !currentValue
63
+ );
64
+ }
42
65
  }
43
- });
66
+ );
44
67
  const handleOptionClick = (option) => {
45
68
  if (option.disabled) {
46
69
  return;
@@ -51,13 +74,46 @@ const Dropdown = ({
51
74
  onChange?.(option.value);
52
75
  setIsOpen(false);
53
76
  };
77
+ const handleMouseEnter = (event) => {
78
+ onMouseEnter?.(event);
79
+ if (isHoverInteraction) {
80
+ setIsOpen(true);
81
+ }
82
+ };
83
+ const handleMouseLeave = (event) => {
84
+ onMouseLeave?.(event);
85
+ if (isHoverInteraction) {
86
+ setIsOpen(false);
87
+ }
88
+ };
89
+ const handleFocus = (event) => {
90
+ onFocus?.(event);
91
+ if (isHoverInteraction) {
92
+ setIsOpen(true);
93
+ }
94
+ };
95
+ const handleBlur = (event) => {
96
+ onBlur?.(event);
97
+ if (!isHoverInteraction) {
98
+ return;
99
+ }
100
+ const nextTarget = event.relatedTarget;
101
+ if (nextTarget instanceof Node && event.currentTarget.contains(
102
+ nextTarget
103
+ )) {
104
+ return;
105
+ }
106
+ setIsOpen(false);
107
+ };
54
108
  react.useEffect(() => {
55
109
  if (!isOpen) {
56
110
  return;
57
111
  }
58
112
  const handleDocumentClick = (event) => {
59
113
  const dropdown = dropdownRef.current;
60
- if (!dropdown || dropdown.contains(event.target)) {
114
+ if (!dropdown || dropdown.contains(
115
+ event.target
116
+ )) {
61
117
  return;
62
118
  }
63
119
  setIsOpen(false);
@@ -67,11 +123,23 @@ const Dropdown = ({
67
123
  setIsOpen(false);
68
124
  }
69
125
  };
70
- document.addEventListener("mousedown", handleDocumentClick);
71
- document.addEventListener("keydown", handleDocumentKeyDown);
126
+ document.addEventListener(
127
+ "mousedown",
128
+ handleDocumentClick
129
+ );
130
+ document.addEventListener(
131
+ "keydown",
132
+ handleDocumentKeyDown
133
+ );
72
134
  return () => {
73
- document.removeEventListener("mousedown", handleDocumentClick);
74
- document.removeEventListener("keydown", handleDocumentKeyDown);
135
+ document.removeEventListener(
136
+ "mousedown",
137
+ handleDocumentClick
138
+ );
139
+ document.removeEventListener(
140
+ "keydown",
141
+ handleDocumentKeyDown
142
+ );
75
143
  };
76
144
  }, [isOpen]);
77
145
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -79,6 +147,10 @@ const Dropdown = ({
79
147
  {
80
148
  ref: dropdownRef,
81
149
  className: classes,
150
+ onMouseEnter: handleMouseEnter,
151
+ onMouseLeave: handleMouseLeave,
152
+ onFocus: handleFocus,
153
+ onBlur: handleBlur,
82
154
  ...props,
83
155
  children: [
84
156
  resolvedTrigger,
@@ -90,10 +162,13 @@ const Dropdown = ({
90
162
  "aria-label": label,
91
163
  children: options.map((option) => {
92
164
  const isSelected = option.value === selectedValue;
93
- const itemClasses = classnames.classnames("dropdown__item", {
94
- "dropdown__item--selected": isSelected,
95
- "dropdown__item--disabled": option.disabled
96
- });
165
+ const itemClasses = classnames.classnames(
166
+ "dropdown__item",
167
+ {
168
+ "dropdown__item--selected": isSelected,
169
+ "dropdown__item--disabled": option.disabled
170
+ }
171
+ );
97
172
  return /* @__PURE__ */ jsxRuntime.jsx(
98
173
  "button",
99
174
  {
@@ -103,7 +178,9 @@ const Dropdown = ({
103
178
  "aria-checked": isSelected,
104
179
  "aria-disabled": option.disabled,
105
180
  disabled: option.disabled,
106
- onClick: () => handleOptionClick(option),
181
+ onClick: () => handleOptionClick(
182
+ option
183
+ ),
107
184
  children: option.label
108
185
  },
109
186
  option.value
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":["useRef","useState","classnames","cloneElement","useEffect","jsxs","jsx"],"mappings":"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","file":"dropdown.cjs","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (event: React.MouseEvent) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?: 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';\n trigger: DropdownTriggerElement;\n onChange?: (value: string) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n trigger,\n onChange,\n className = '',\n ...props\n}) => {\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [isOpen, setIsOpen] = useState(false);\n const [internalValue, setInternalValue] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const classes = classnames('dropdown', className, {\n 'dropdown--open': isOpen,\n 'dropdown--top-start': align === 'top-start',\n 'dropdown--top-end': align === 'top-end',\n 'dropdown--bottom-start': align === 'bottom-start',\n 'dropdown--bottom-end': align === 'bottom-end',\n });\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(triggerElement, {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (event: React.MouseEvent) => {\n triggerElement.props.onClick?.(event);\n\n setIsOpen((currentValue) => !currentValue);\n },\n });\n\n const handleOptionClick = (option: DropdownOption) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n setIsOpen(false);\n };\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (event: MouseEvent) => {\n const dropdown = dropdownRef.current;\n\n if (!dropdown || dropdown.contains(event.target as Node)) {\n return;\n }\n\n setIsOpen(false);\n };\n\n const handleDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleDocumentClick);\n document.addEventListener('keydown', handleDocumentKeyDown);\n\n return () => {\n document.removeEventListener('mousedown', handleDocumentClick);\n document.removeEventListener('keydown', handleDocumentKeyDown);\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value === selectedValue;\n\n const itemClasses = classnames('dropdown__item', {\n 'dropdown__item--selected': isSelected,\n 'dropdown__item--disabled': option.disabled,\n });\n\n return (\n <button\n key={option.value}\n className={itemClasses}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={isSelected}\n aria-disabled={option.disabled}\n disabled={option.disabled}\n onClick={() => handleOptionClick(option)}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;"]}
1
+ {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":["useRef","useState","classnames","cloneElement","useEffect","jsxs","jsx"],"mappings":";;;;;;;AAqDA,MAAM,WAAoC,CAAC;AAAA,EACzC,OAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA,GAAQ,UAAA;AAAA,EACR,KAAA,GAAQ,cAAA;AAAA,EACR,WAAA,GAAc,OAAA;AAAA,EACd,OAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,YAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,WAAA,GACJA,aAAuB,IAAI,CAAA;AAE7B,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GACtBC,eAAS,KAAK,CAAA;AAEhB,EAAA,MAAM;AAAA,IACJ,aAAA;AAAA,IACA;AAAA,GACF,GAAIA,eAAS,YAAY,CAAA;AAEzB,EAAA,MAAM,gBACJ,KAAA,IAAS,aAAA;AAEX,EAAA,MAAM,qBACJ,WAAA,KAAgB,OAAA;AAElB,EAAA,MAAM,OAAA,GAAUC,qBAAA;AAAA,IACd,UAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,gBAAA,EAAkB,MAAA;AAAA,MAClB,uBACE,KAAA,KAAU,WAAA;AAAA,MACZ,qBACE,KAAA,KAAU,SAAA;AAAA,MACZ,0BACE,KAAA,KAAU,cAAA;AAAA,MACZ,wBACE,KAAA,KAAU;AAAA;AACd,GACF;AAEA,EAAA,MAAM,cAAA,GACJ,OAAA;AAEF,EAAA,MAAM,cAAA,GAAiBA,qBAAA;AAAA,IACrB,mBAAA;AAAA,IACA,eAAe,KAAA,CAAM;AAAA,GACvB;AAEA,EAAA,MAAM,eAAA,GAAkBC,kBAAA;AAAA,IACtB,cAAA;AAAA,IACA;AAAA,MACE,SAAA,EAAW,cAAA;AAAA,MACX,eAAA,EAAiB,MAAA;AAAA,MACjB,eAAA,EAAiB,MAAA;AAAA,MAEjB,OAAA,EAAS,CACP,KAAA,KACG;AACH,QAAA,cAAA,CAAe,KAAA,CAAM,OAAA;AAAA,UACnB;AAAA,SACF;AAEA,QAAA,IAAI,kBAAA,EAAoB;AACtB,UAAA;AAAA,QACF;AAEA,QAAA,SAAA;AAAA,UACE,CAAC,iBACC,CAAC;AAAA,SACL;AAAA,MACF;AAAA;AACF,GACF;AAEA,EAAA,MAAM,iBAAA,GAAoB,CACxB,MAAA,KACG;AACH,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,gBAAA,CAAiB,OAAO,KAAK,CAAA;AAAA,IAC/B;AAEA,IAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AACvB,IAAA,SAAA,CAAU,KAAK,CAAA;AAAA,EACjB,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,YAAA,GAAe,KAAK,CAAA;AAEpB,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,YAAA,GAAe,KAAK,CAAA;AAEpB,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,SAAA,CAAU,KAAK,CAAA;AAAA,IACjB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KACG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CACjB,KAAA,KACG;AACH,IAAA,MAAA,GAAS,KAAK,CAAA;AAEd,IAAA,IAAI,CAAC,kBAAA,EAAoB;AACvB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aACJ,KAAA,CAAM,aAAA;AAER,IAAA,IACE,UAAA,YAAsB,IAAA,IACtB,KAAA,CAAM,aAAA,CAAc,QAAA;AAAA,MAClB;AAAA,KACF,EACA;AACA,MAAA;AAAA,IACF;AAEA,IAAA,SAAA,CAAU,KAAK,CAAA;AAAA,EACjB,CAAA;AAEA,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAC1B,KAAA,KACG;AACH,MAAA,MAAM,WACJ,WAAA,CAAY,OAAA;AAEd,MAAA,IACE,CAAC,YACD,QAAA,CAAS,QAAA;AAAA,QACP,KAAA,CAAM;AAAA,OACR,EACA;AACA,QAAA;AAAA,MACF;AAEA,MAAA,SAAA,CAAU,KAAK,CAAA;AAAA,IACjB,CAAA;AAEA,IAAA,MAAM,qBAAA,GAAwB,CAC5B,KAAA,KACG;AACH,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA;AAAA,MACP,WAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,QAAA,CAAS,gBAAA;AAAA,MACP,SAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA;AAAA,QACP,WAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,QAAA,CAAS,mBAAA;AAAA,QACP,SAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,WAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,YAAA,EACE,gBAAA;AAAA,MAEF,YAAA,EACE,gBAAA;AAAA,MAEF,OAAA,EAAS,WAAA;AAAA,MACT,MAAA,EAAQ,UAAA;AAAA,MACP,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,eAAA;AAAA,QAEA,MAAA,oBACCC,cAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,gBAAA;AAAA,YACV,IAAA,EAAK,MAAA;AAAA,YACL,YAAA,EAAY,KAAA;AAAA,YAEX,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvB,cAAA,MAAM,UAAA,GACJ,OAAO,KAAA,KACP,aAAA;AAEF,cAAA,MAAM,WAAA,GACJJ,qBAAA;AAAA,gBACE,gBAAA;AAAA,gBACA;AAAA,kBACE,0BAAA,EACE,UAAA;AAAA,kBACF,4BACE,MAAA,CAAO;AAAA;AACX,eACF;AAEF,cAAA,uBACEI,cAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBAEC,SAAA,EACE,WAAA;AAAA,kBAEF,IAAA,EAAK,QAAA;AAAA,kBACL,IAAA,EAAK,eAAA;AAAA,kBACL,cAAA,EACE,UAAA;AAAA,kBAEF,iBACE,MAAA,CAAO,QAAA;AAAA,kBAET,UACE,MAAA,CAAO,QAAA;AAAA,kBAET,SAAS,MACP,iBAAA;AAAA,oBACE;AAAA,mBACF;AAAA,kBAGD,QAAA,EAAA,MAAA,CAAO;AAAA,iBAAA;AAAA,gBArBH,MAAA,CAAO;AAAA,eAsBd;AAAA,YAEJ,CAAC;AAAA;AAAA;AACH;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"dropdown.cjs","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport type DropdownInteraction =\n | 'click'\n | 'hover';\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (\n event: React.MouseEvent,\n ) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange'\n > {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?:\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n interaction?: DropdownInteraction;\n trigger: DropdownTriggerElement;\n onChange?: (\n value: string,\n ) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n interaction = 'click',\n trigger,\n onChange,\n className = '',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}) => {\n const dropdownRef =\n useRef<HTMLDivElement>(null);\n\n const [isOpen, setIsOpen] =\n useState(false);\n\n const [\n internalValue,\n setInternalValue,\n ] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const isHoverInteraction =\n interaction === 'hover';\n\n const classes = classnames(\n 'dropdown',\n className,\n {\n 'dropdown--open': isOpen,\n 'dropdown--top-start':\n align === 'top-start',\n 'dropdown--top-end':\n align === 'top-end',\n 'dropdown--bottom-start':\n align === 'bottom-start',\n 'dropdown--bottom-end':\n align === 'bottom-end',\n },\n );\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(\n triggerElement,\n {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n\n onClick: (\n event: React.MouseEvent,\n ) => {\n triggerElement.props.onClick?.(\n event,\n );\n\n if (isHoverInteraction) {\n return;\n }\n\n setIsOpen(\n (currentValue) =>\n !currentValue,\n );\n },\n },\n );\n\n const handleOptionClick = (\n option: DropdownOption,\n ) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n setIsOpen(false);\n };\n\n const handleMouseEnter = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseEnter?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleMouseLeave = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseLeave?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(false);\n }\n };\n\n const handleFocus = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onFocus?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleBlur = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onBlur?.(event);\n\n if (!isHoverInteraction) {\n return;\n }\n\n const nextTarget =\n event.relatedTarget;\n\n if (\n nextTarget instanceof Node &&\n event.currentTarget.contains(\n nextTarget,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (\n event: MouseEvent,\n ) => {\n const dropdown =\n dropdownRef.current;\n\n if (\n !dropdown ||\n dropdown.contains(\n event.target as Node,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n const handleDocumentKeyDown = (\n event: KeyboardEvent,\n ) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n document.addEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.addEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n\n return () => {\n document.removeEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.removeEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n onMouseEnter={\n handleMouseEnter\n }\n onMouseLeave={\n handleMouseLeave\n }\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value ===\n selectedValue;\n\n const itemClasses =\n classnames(\n 'dropdown__item',\n {\n 'dropdown__item--selected':\n isSelected,\n 'dropdown__item--disabled':\n option.disabled,\n },\n );\n\n return (\n <button\n key={option.value}\n className={\n itemClasses\n }\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={\n isSelected\n }\n aria-disabled={\n option.disabled\n }\n disabled={\n option.disabled\n }\n onClick={() =>\n handleOptionClick(\n option,\n )\n }\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;\n"]}