typeChecks.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { ROUNDNESS } from "../constants";
  2. import { AppState } from "../types";
  3. import {
  4. ExcalidrawElement,
  5. ExcalidrawTextElement,
  6. ExcalidrawLinearElement,
  7. ExcalidrawBindableElement,
  8. ExcalidrawGenericElement,
  9. ExcalidrawFreeDrawElement,
  10. InitializedExcalidrawImageElement,
  11. ExcalidrawImageElement,
  12. ExcalidrawTextElementWithContainer,
  13. ExcalidrawTextContainer,
  14. RoundnessType,
  15. } from "./types";
  16. export const isGenericElement = (
  17. element: ExcalidrawElement | null,
  18. ): element is ExcalidrawGenericElement => {
  19. return (
  20. element != null &&
  21. (element.type === "selection" ||
  22. element.type === "rectangle" ||
  23. element.type === "diamond" ||
  24. element.type === "ellipse")
  25. );
  26. };
  27. export const isInitializedImageElement = (
  28. element: ExcalidrawElement | null,
  29. ): element is InitializedExcalidrawImageElement => {
  30. return !!element && element.type === "image" && !!element.fileId;
  31. };
  32. export const isImageElement = (
  33. element: ExcalidrawElement | null,
  34. ): element is ExcalidrawImageElement => {
  35. return !!element && element.type === "image";
  36. };
  37. export const isTextElement = (
  38. element: ExcalidrawElement | null,
  39. ): element is ExcalidrawTextElement => {
  40. return element != null && element.type === "text";
  41. };
  42. export const isFreeDrawElement = (
  43. element?: ExcalidrawElement | null,
  44. ): element is ExcalidrawFreeDrawElement => {
  45. return element != null && isFreeDrawElementType(element.type);
  46. };
  47. export const isFreeDrawElementType = (
  48. elementType: ExcalidrawElement["type"],
  49. ): boolean => {
  50. return elementType === "freedraw";
  51. };
  52. export const isLinearElement = (
  53. element?: ExcalidrawElement | null,
  54. ): element is ExcalidrawLinearElement => {
  55. return element != null && isLinearElementType(element.type);
  56. };
  57. export const isArrowElement = (
  58. element?: ExcalidrawElement | null,
  59. ): element is ExcalidrawLinearElement => {
  60. return element != null && element.type === "arrow";
  61. };
  62. export const isLinearElementType = (
  63. elementType: AppState["activeTool"]["type"],
  64. ): boolean => {
  65. return (
  66. elementType === "arrow" || elementType === "line" // || elementType === "freedraw"
  67. );
  68. };
  69. export const isBindingElement = (
  70. element?: ExcalidrawElement | null,
  71. includeLocked = true,
  72. ): element is ExcalidrawLinearElement => {
  73. return (
  74. element != null &&
  75. (!element.locked || includeLocked === true) &&
  76. isBindingElementType(element.type)
  77. );
  78. };
  79. export const isBindingElementType = (
  80. elementType: AppState["activeTool"]["type"],
  81. ): boolean => {
  82. return elementType === "arrow";
  83. };
  84. export const isBindableElement = (
  85. element: ExcalidrawElement | null,
  86. includeLocked = true,
  87. ): element is ExcalidrawBindableElement => {
  88. return (
  89. element != null &&
  90. (!element.locked || includeLocked === true) &&
  91. (element.type === "rectangle" ||
  92. element.type === "diamond" ||
  93. element.type === "ellipse" ||
  94. element.type === "image" ||
  95. (element.type === "text" && !element.containerId))
  96. );
  97. };
  98. export const isTextBindableContainer = (
  99. element: ExcalidrawElement | null,
  100. includeLocked = true,
  101. ): element is ExcalidrawTextContainer => {
  102. return (
  103. element != null &&
  104. (!element.locked || includeLocked === true) &&
  105. (element.type === "rectangle" ||
  106. element.type === "diamond" ||
  107. element.type === "ellipse" ||
  108. element.type === "image" ||
  109. isArrowElement(element))
  110. );
  111. };
  112. export const isExcalidrawElement = (element: any): boolean => {
  113. return (
  114. element?.type === "text" ||
  115. element?.type === "diamond" ||
  116. element?.type === "rectangle" ||
  117. element?.type === "ellipse" ||
  118. element?.type === "arrow" ||
  119. element?.type === "freedraw" ||
  120. element?.type === "line"
  121. );
  122. };
  123. export const hasBoundTextElement = (
  124. element: ExcalidrawElement | null,
  125. ): element is MarkNonNullable<ExcalidrawBindableElement, "boundElements"> => {
  126. return (
  127. isBindableElement(element) &&
  128. !!element.boundElements?.some(({ type }) => type === "text")
  129. );
  130. };
  131. export const isBoundToContainer = (
  132. element: ExcalidrawElement | null,
  133. ): element is ExcalidrawTextElementWithContainer => {
  134. return (
  135. element !== null &&
  136. "containerId" in element &&
  137. element.containerId !== null &&
  138. isTextElement(element)
  139. );
  140. };
  141. export const isUsingAdaptiveRadius = (type: string) => type === "rectangle";
  142. export const isUsingProportionalRadius = (type: string) =>
  143. type === "line" || type === "arrow" || type === "diamond";
  144. export const canApplyRoundnessTypeToElement = (
  145. roundnessType: RoundnessType,
  146. element: ExcalidrawElement,
  147. ) => {
  148. if (
  149. (roundnessType === ROUNDNESS.ADAPTIVE_RADIUS ||
  150. // if legacy roundness, it can be applied to elements that currently
  151. // use adaptive radius
  152. roundnessType === ROUNDNESS.LEGACY) &&
  153. isUsingAdaptiveRadius(element.type)
  154. ) {
  155. return true;
  156. }
  157. if (
  158. roundnessType === ROUNDNESS.PROPORTIONAL_RADIUS &&
  159. isUsingProportionalRadius(element.type)
  160. ) {
  161. return true;
  162. }
  163. return false;
  164. };
  165. export const getDefaultRoundnessTypeForElement = (
  166. element: ExcalidrawElement,
  167. ) => {
  168. if (
  169. element.type === "arrow" ||
  170. element.type === "line" ||
  171. element.type === "diamond"
  172. ) {
  173. return {
  174. type: ROUNDNESS.PROPORTIONAL_RADIUS,
  175. };
  176. }
  177. if (element.type === "rectangle") {
  178. return {
  179. type: ROUNDNESS.ADAPTIVE_RADIUS,
  180. };
  181. }
  182. return null;
  183. };