dialog.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { Dialog as Kobalte } from "@kobalte/core/dialog"
  2. import { ComponentProps, JSXElement, Match, ParentProps, Show, Switch } from "solid-js"
  3. import { useI18n } from "../context/i18n"
  4. import { IconButton } from "./icon-button"
  5. export interface DialogProps extends ParentProps {
  6. title?: JSXElement
  7. description?: JSXElement
  8. action?: JSXElement
  9. size?: "normal" | "large" | "x-large"
  10. class?: ComponentProps<"div">["class"]
  11. classList?: ComponentProps<"div">["classList"]
  12. fit?: boolean
  13. transition?: boolean
  14. }
  15. export function Dialog(props: DialogProps) {
  16. const i18n = useI18n()
  17. return (
  18. <div
  19. data-component="dialog"
  20. data-fit={props.fit ? true : undefined}
  21. data-size={props.size || "normal"}
  22. data-transition={props.transition ? true : undefined}
  23. >
  24. <div data-slot="dialog-container">
  25. <Kobalte.Content
  26. data-slot="dialog-content"
  27. data-no-header={!props.title && !props.action ? "" : undefined}
  28. classList={{
  29. ...props.classList,
  30. [props.class ?? ""]: !!props.class,
  31. }}
  32. onOpenAutoFocus={(e) => {
  33. const target = e.currentTarget as HTMLElement | null
  34. const autofocusEl = target?.querySelector("[autofocus]") as HTMLElement | null
  35. if (autofocusEl) {
  36. e.preventDefault()
  37. autofocusEl.focus()
  38. }
  39. }}
  40. >
  41. <Show when={props.title || props.action}>
  42. <div data-slot="dialog-header">
  43. <Show when={props.title}>
  44. <Kobalte.Title data-slot="dialog-title">{props.title}</Kobalte.Title>
  45. </Show>
  46. <Switch>
  47. <Match when={props.action}>{props.action}</Match>
  48. <Match when={true}>
  49. <Kobalte.CloseButton
  50. data-slot="dialog-close-button"
  51. as={IconButton}
  52. icon="close"
  53. variant="ghost"
  54. aria-label={i18n.t("ui.common.close")}
  55. />
  56. </Match>
  57. </Switch>
  58. </div>
  59. </Show>
  60. <Show when={props.description}>
  61. <Kobalte.Description data-slot="dialog-description" style={{ "margin-left": "-4px" }}>
  62. {props.description}
  63. </Kobalte.Description>
  64. </Show>
  65. <div data-slot="dialog-body">{props.children}</div>
  66. </Kobalte.Content>
  67. </div>
  68. </div>
  69. )
  70. }