@instructure/ui-form-field 11.6.0 → 11.6.1-snapshot-129

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 (248) hide show
  1. package/CHANGELOG.md +46 -300
  2. package/es/FormField/{index.js → v1/index.js} +1 -1
  3. package/es/FormField/v2/index.js +78 -0
  4. package/es/FormField/v2/props.js +26 -0
  5. package/es/FormFieldGroup/{index.js → v1/index.js} +5 -4
  6. package/es/FormFieldGroup/v2/index.js +130 -0
  7. package/es/FormFieldGroup/v2/props.js +26 -0
  8. package/es/FormFieldGroup/v2/styles.js +49 -0
  9. package/es/FormFieldLabel/{index.js → v1/index.js} +1 -1
  10. package/es/FormFieldLabel/v2/index.js +83 -0
  11. package/es/FormFieldLabel/v2/props.js +26 -0
  12. package/es/FormFieldLabel/v2/styles.js +62 -0
  13. package/es/FormFieldLabel/v2/theme.js +52 -0
  14. package/es/FormFieldLayout/{index.js → v1/index.js} +2 -2
  15. package/es/FormFieldLayout/{styles.js → v1/styles.js} +2 -2
  16. package/es/FormFieldLayout/v2/index.js +207 -0
  17. package/es/FormFieldLayout/v2/props.js +26 -0
  18. package/es/FormFieldLayout/v2/styles.js +171 -0
  19. package/es/FormFieldMessage/{index.js → v1/index.js} +1 -1
  20. package/es/FormFieldMessage/v2/index.js +96 -0
  21. package/es/FormFieldMessage/v2/props.js +26 -0
  22. package/es/FormFieldMessage/v2/styles.js +69 -0
  23. package/es/FormFieldMessages/{index.js → v1/index.js} +2 -2
  24. package/es/FormFieldMessages/v2/index.js +88 -0
  25. package/es/FormFieldMessages/v2/props.js +26 -0
  26. package/es/FormFieldMessages/v2/styles.js +50 -0
  27. package/es/{index.js → exports/a.js} +6 -6
  28. package/es/exports/b.js +29 -0
  29. package/lib/FormField/{index.js → v1/index.js} +3 -3
  30. package/lib/FormField/v2/index.js +85 -0
  31. package/lib/FormField/v2/props.js +31 -0
  32. package/lib/FormFieldGroup/{index.js → v1/index.js} +11 -10
  33. package/lib/FormFieldGroup/v2/index.js +136 -0
  34. package/lib/FormFieldGroup/v2/props.js +31 -0
  35. package/lib/FormFieldGroup/v2/styles.js +55 -0
  36. package/lib/FormFieldLabel/{index.js → v1/index.js} +1 -1
  37. package/lib/FormFieldLabel/v2/index.js +89 -0
  38. package/lib/FormFieldLabel/v2/props.js +31 -0
  39. package/lib/FormFieldLabel/v2/styles.js +68 -0
  40. package/lib/FormFieldLabel/v2/theme.js +58 -0
  41. package/lib/FormFieldLayout/{index.js → v1/index.js} +3 -3
  42. package/lib/FormFieldLayout/{styles.js → v1/styles.js} +1 -1
  43. package/lib/FormFieldLayout/v2/index.js +220 -0
  44. package/lib/FormFieldLayout/v2/props.js +31 -0
  45. package/lib/FormFieldLayout/v2/styles.js +177 -0
  46. package/lib/FormFieldMessage/{index.js → v1/index.js} +2 -2
  47. package/lib/FormFieldMessage/v2/index.js +101 -0
  48. package/lib/FormFieldMessage/v2/props.js +31 -0
  49. package/lib/FormFieldMessage/v2/styles.js +75 -0
  50. package/lib/FormFieldMessages/{index.js → v1/index.js} +3 -3
  51. package/lib/FormFieldMessages/v2/index.js +93 -0
  52. package/lib/FormFieldMessages/v2/props.js +31 -0
  53. package/lib/FormFieldMessages/v2/styles.js +56 -0
  54. package/lib/{index.js → exports/a.js} +12 -12
  55. package/lib/exports/b.js +47 -0
  56. package/package.json +43 -21
  57. package/src/FormField/{index.tsx → v1/index.tsx} +1 -1
  58. package/src/FormField/{props.ts → v1/props.ts} +1 -1
  59. package/src/FormField/v2/README.md +43 -0
  60. package/src/FormField/v2/index.tsx +87 -0
  61. package/src/FormField/v2/props.ts +104 -0
  62. package/src/FormFieldGroup/{index.tsx → v1/index.tsx} +6 -4
  63. package/src/FormFieldGroup/{props.ts → v1/props.ts} +2 -2
  64. package/src/FormFieldGroup/v2/README.md +114 -0
  65. package/src/FormFieldGroup/v2/index.tsx +182 -0
  66. package/src/FormFieldGroup/v2/props.ts +103 -0
  67. package/src/FormFieldGroup/v2/styles.ts +58 -0
  68. package/src/FormFieldLabel/{index.tsx → v1/index.tsx} +1 -1
  69. package/src/FormFieldLabel/v2/index.tsx +95 -0
  70. package/src/FormFieldLabel/v2/props.ts +49 -0
  71. package/src/FormFieldLabel/v2/styles.ts +74 -0
  72. package/src/FormFieldLabel/v2/theme.ts +56 -0
  73. package/src/FormFieldLayout/{index.tsx → v1/index.tsx} +2 -2
  74. package/src/FormFieldLayout/{props.ts → v1/props.ts} +1 -1
  75. package/src/FormFieldLayout/{styles.ts → v1/styles.ts} +2 -2
  76. package/src/FormFieldLayout/v2/index.tsx +237 -0
  77. package/src/FormFieldLayout/v2/props.ts +157 -0
  78. package/src/FormFieldLayout/v2/styles.ts +209 -0
  79. package/src/FormFieldMessage/{index.tsx → v1/index.tsx} +1 -1
  80. package/src/FormFieldMessage/{props.ts → v1/props.ts} +4 -1
  81. package/src/FormFieldMessage/{styles.ts → v1/styles.ts} +2 -3
  82. package/src/FormFieldMessage/v2/index.tsx +104 -0
  83. package/src/FormFieldMessage/v2/props.ts +48 -0
  84. package/src/FormFieldMessage/v2/styles.ts +76 -0
  85. package/src/FormFieldMessages/{index.tsx → v1/index.tsx} +2 -2
  86. package/src/FormFieldMessages/{props.ts → v1/props.ts} +1 -1
  87. package/src/FormFieldMessages/v2/index.tsx +99 -0
  88. package/src/FormFieldMessages/v2/props.ts +59 -0
  89. package/src/FormFieldMessages/v2/styles.ts +55 -0
  90. package/src/{index.ts → exports/a.ts} +17 -13
  91. package/src/exports/b.ts +43 -0
  92. package/tsconfig.build.json +1 -0
  93. package/tsconfig.build.tsbuildinfo +1 -1
  94. package/types/FormField/v1/index.d.ts.map +1 -0
  95. package/types/FormField/{props.d.ts → v1/props.d.ts} +1 -1
  96. package/types/FormField/v1/props.d.ts.map +1 -0
  97. package/types/FormField/v2/index.d.ts +23 -0
  98. package/types/FormField/v2/index.d.ts.map +1 -0
  99. package/types/FormField/v2/props.d.ts +57 -0
  100. package/types/FormField/v2/props.d.ts.map +1 -0
  101. package/types/FormFieldGroup/{index.d.ts → v1/index.d.ts} +1 -1
  102. package/types/FormFieldGroup/v1/index.d.ts.map +1 -0
  103. package/types/FormFieldGroup/{props.d.ts → v1/props.d.ts} +2 -2
  104. package/types/FormFieldGroup/v1/props.d.ts.map +1 -0
  105. package/types/FormFieldGroup/v1/styles.d.ts.map +1 -0
  106. package/types/FormFieldGroup/v1/theme.d.ts.map +1 -0
  107. package/types/FormFieldGroup/v2/index.d.ts +45 -0
  108. package/types/FormFieldGroup/v2/index.d.ts.map +1 -0
  109. package/types/FormFieldGroup/v2/props.d.ts +48 -0
  110. package/types/FormFieldGroup/v2/props.d.ts.map +1 -0
  111. package/types/FormFieldGroup/v2/styles.d.ts +14 -0
  112. package/types/FormFieldGroup/v2/styles.d.ts.map +1 -0
  113. package/types/FormFieldLabel/v1/index.d.ts.map +1 -0
  114. package/types/FormFieldLabel/v1/props.d.ts.map +1 -0
  115. package/types/FormFieldLabel/v1/styles.d.ts.map +1 -0
  116. package/types/FormFieldLabel/v1/theme.d.ts.map +1 -0
  117. package/types/FormFieldLabel/v2/index.d.ts +38 -0
  118. package/types/FormFieldLabel/v2/index.d.ts.map +1 -0
  119. package/types/FormFieldLabel/v2/props.d.ts +14 -0
  120. package/types/FormFieldLabel/v2/props.d.ts.map +1 -0
  121. package/types/FormFieldLabel/v2/styles.d.ts +15 -0
  122. package/types/FormFieldLabel/v2/styles.d.ts.map +1 -0
  123. package/types/FormFieldLabel/v2/theme.d.ts +10 -0
  124. package/types/FormFieldLabel/v2/theme.d.ts.map +1 -0
  125. package/types/FormFieldLayout/v1/index.d.ts.map +1 -0
  126. package/types/FormFieldLayout/{props.d.ts → v1/props.d.ts} +1 -1
  127. package/types/FormFieldLayout/v1/props.d.ts.map +1 -0
  128. package/types/FormFieldLayout/v1/styles.d.ts.map +1 -0
  129. package/types/FormFieldLayout/v1/theme.d.ts.map +1 -0
  130. package/types/FormFieldLayout/v2/index.d.ts +14 -0
  131. package/types/FormFieldLayout/v2/index.d.ts.map +1 -0
  132. package/types/FormFieldLayout/v2/props.d.ts +90 -0
  133. package/types/FormFieldLayout/v2/props.d.ts.map +1 -0
  134. package/types/FormFieldLayout/v2/styles.d.ts +25 -0
  135. package/types/FormFieldLayout/v2/styles.d.ts.map +1 -0
  136. package/types/FormFieldMessage/{index.d.ts → v1/index.d.ts} +2 -2
  137. package/types/FormFieldMessage/v1/index.d.ts.map +1 -0
  138. package/types/FormFieldMessage/{props.d.ts → v1/props.d.ts} +1 -1
  139. package/types/FormFieldMessage/v1/props.d.ts.map +1 -0
  140. package/types/FormFieldMessage/v1/styles.d.ts.map +1 -0
  141. package/types/FormFieldMessage/v1/theme.d.ts.map +1 -0
  142. package/types/FormFieldMessage/v2/index.d.ts +24 -0
  143. package/types/FormFieldMessage/v2/index.d.ts.map +1 -0
  144. package/types/FormFieldMessage/v2/props.d.ts +16 -0
  145. package/types/FormFieldMessage/v2/props.d.ts.map +1 -0
  146. package/types/FormFieldMessage/v2/styles.d.ts +18 -0
  147. package/types/FormFieldMessage/v2/styles.d.ts.map +1 -0
  148. package/types/FormFieldMessages/{index.d.ts → v1/index.d.ts} +1 -1
  149. package/types/FormFieldMessages/v1/index.d.ts.map +1 -0
  150. package/types/FormFieldMessages/{props.d.ts → v1/props.d.ts} +1 -1
  151. package/types/FormFieldMessages/v1/props.d.ts.map +1 -0
  152. package/types/FormFieldMessages/v1/styles.d.ts.map +1 -0
  153. package/types/FormFieldMessages/v1/theme.d.ts.map +1 -0
  154. package/types/FormFieldMessages/v2/index.d.ts +36 -0
  155. package/types/FormFieldMessages/v2/index.d.ts.map +1 -0
  156. package/types/FormFieldMessages/v2/props.d.ts +25 -0
  157. package/types/FormFieldMessages/v2/props.d.ts.map +1 -0
  158. package/types/FormFieldMessages/v2/styles.d.ts +14 -0
  159. package/types/FormFieldMessages/v2/styles.d.ts.map +1 -0
  160. package/types/exports/a.d.ts +14 -0
  161. package/types/exports/a.d.ts.map +1 -0
  162. package/types/exports/b.d.ts +14 -0
  163. package/types/exports/b.d.ts.map +1 -0
  164. package/types/utils/v1/FormPropTypes.d.ts.map +1 -0
  165. package/types/FormField/index.d.ts.map +0 -1
  166. package/types/FormField/props.d.ts.map +0 -1
  167. package/types/FormFieldGroup/index.d.ts.map +0 -1
  168. package/types/FormFieldGroup/props.d.ts.map +0 -1
  169. package/types/FormFieldGroup/styles.d.ts.map +0 -1
  170. package/types/FormFieldGroup/theme.d.ts.map +0 -1
  171. package/types/FormFieldLabel/index.d.ts.map +0 -1
  172. package/types/FormFieldLabel/props.d.ts.map +0 -1
  173. package/types/FormFieldLabel/styles.d.ts.map +0 -1
  174. package/types/FormFieldLabel/theme.d.ts.map +0 -1
  175. package/types/FormFieldLayout/index.d.ts.map +0 -1
  176. package/types/FormFieldLayout/props.d.ts.map +0 -1
  177. package/types/FormFieldLayout/styles.d.ts.map +0 -1
  178. package/types/FormFieldLayout/theme.d.ts.map +0 -1
  179. package/types/FormFieldMessage/index.d.ts.map +0 -1
  180. package/types/FormFieldMessage/props.d.ts.map +0 -1
  181. package/types/FormFieldMessage/styles.d.ts.map +0 -1
  182. package/types/FormFieldMessage/theme.d.ts.map +0 -1
  183. package/types/FormFieldMessages/index.d.ts.map +0 -1
  184. package/types/FormFieldMessages/props.d.ts.map +0 -1
  185. package/types/FormFieldMessages/styles.d.ts.map +0 -1
  186. package/types/FormFieldMessages/theme.d.ts.map +0 -1
  187. package/types/FormPropTypes.d.ts.map +0 -1
  188. package/types/index.d.ts +0 -14
  189. package/types/index.d.ts.map +0 -1
  190. /package/es/FormField/{props.js → v1/props.js} +0 -0
  191. /package/es/FormFieldGroup/{props.js → v1/props.js} +0 -0
  192. /package/es/FormFieldGroup/{styles.js → v1/styles.js} +0 -0
  193. /package/es/FormFieldGroup/{theme.js → v1/theme.js} +0 -0
  194. /package/es/FormFieldLabel/{props.js → v1/props.js} +0 -0
  195. /package/es/FormFieldLabel/{styles.js → v1/styles.js} +0 -0
  196. /package/es/FormFieldLabel/{theme.js → v1/theme.js} +0 -0
  197. /package/es/FormFieldLayout/{props.js → v1/props.js} +0 -0
  198. /package/es/FormFieldLayout/{theme.js → v1/theme.js} +0 -0
  199. /package/es/FormFieldMessage/{props.js → v1/props.js} +0 -0
  200. /package/es/FormFieldMessage/{styles.js → v1/styles.js} +0 -0
  201. /package/es/FormFieldMessage/{theme.js → v1/theme.js} +0 -0
  202. /package/es/FormFieldMessages/{props.js → v1/props.js} +0 -0
  203. /package/es/FormFieldMessages/{styles.js → v1/styles.js} +0 -0
  204. /package/es/FormFieldMessages/{theme.js → v1/theme.js} +0 -0
  205. /package/es/{FormPropTypes.js → utils/v1/FormPropTypes.js} +0 -0
  206. /package/lib/FormField/{props.js → v1/props.js} +0 -0
  207. /package/lib/FormFieldGroup/{props.js → v1/props.js} +0 -0
  208. /package/lib/FormFieldGroup/{styles.js → v1/styles.js} +0 -0
  209. /package/lib/FormFieldGroup/{theme.js → v1/theme.js} +0 -0
  210. /package/lib/FormFieldLabel/{props.js → v1/props.js} +0 -0
  211. /package/lib/FormFieldLabel/{styles.js → v1/styles.js} +0 -0
  212. /package/lib/FormFieldLabel/{theme.js → v1/theme.js} +0 -0
  213. /package/lib/FormFieldLayout/{props.js → v1/props.js} +0 -0
  214. /package/lib/FormFieldLayout/{theme.js → v1/theme.js} +0 -0
  215. /package/lib/FormFieldMessage/{props.js → v1/props.js} +0 -0
  216. /package/lib/FormFieldMessage/{styles.js → v1/styles.js} +0 -0
  217. /package/lib/FormFieldMessage/{theme.js → v1/theme.js} +0 -0
  218. /package/lib/FormFieldMessages/{props.js → v1/props.js} +0 -0
  219. /package/lib/FormFieldMessages/{styles.js → v1/styles.js} +0 -0
  220. /package/lib/FormFieldMessages/{theme.js → v1/theme.js} +0 -0
  221. /package/lib/{FormPropTypes.js → utils/v1/FormPropTypes.js} +0 -0
  222. /package/src/FormField/{README.md → v1/README.md} +0 -0
  223. /package/src/FormFieldGroup/{README.md → v1/README.md} +0 -0
  224. /package/src/FormFieldGroup/{styles.ts → v1/styles.ts} +0 -0
  225. /package/src/FormFieldGroup/{theme.ts → v1/theme.ts} +0 -0
  226. /package/src/FormFieldLabel/{props.ts → v1/props.ts} +0 -0
  227. /package/src/FormFieldLabel/{styles.ts → v1/styles.ts} +0 -0
  228. /package/src/FormFieldLabel/{theme.ts → v1/theme.ts} +0 -0
  229. /package/src/FormFieldLayout/{theme.ts → v1/theme.ts} +0 -0
  230. /package/src/FormFieldMessage/{theme.ts → v1/theme.ts} +0 -0
  231. /package/src/FormFieldMessages/{styles.ts → v1/styles.ts} +0 -0
  232. /package/src/FormFieldMessages/{theme.ts → v1/theme.ts} +0 -0
  233. /package/src/{FormPropTypes.ts → utils/v1/FormPropTypes.ts} +0 -0
  234. /package/types/FormField/{index.d.ts → v1/index.d.ts} +0 -0
  235. /package/types/FormFieldGroup/{styles.d.ts → v1/styles.d.ts} +0 -0
  236. /package/types/FormFieldGroup/{theme.d.ts → v1/theme.d.ts} +0 -0
  237. /package/types/FormFieldLabel/{index.d.ts → v1/index.d.ts} +0 -0
  238. /package/types/FormFieldLabel/{props.d.ts → v1/props.d.ts} +0 -0
  239. /package/types/FormFieldLabel/{styles.d.ts → v1/styles.d.ts} +0 -0
  240. /package/types/FormFieldLabel/{theme.d.ts → v1/theme.d.ts} +0 -0
  241. /package/types/FormFieldLayout/{index.d.ts → v1/index.d.ts} +0 -0
  242. /package/types/FormFieldLayout/{styles.d.ts → v1/styles.d.ts} +0 -0
  243. /package/types/FormFieldLayout/{theme.d.ts → v1/theme.d.ts} +0 -0
  244. /package/types/FormFieldMessage/{styles.d.ts → v1/styles.d.ts} +0 -0
  245. /package/types/FormFieldMessage/{theme.d.ts → v1/theme.d.ts} +0 -0
  246. /package/types/FormFieldMessages/{styles.d.ts → v1/styles.d.ts} +0 -0
  247. /package/types/FormFieldMessages/{theme.d.ts → v1/theme.d.ts} +0 -0
  248. /package/types/{FormPropTypes.d.ts → utils/v1/FormPropTypes.d.ts} +0 -0
@@ -0,0 +1,237 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { forwardRef, useEffect, useState, useCallback } from 'react'
26
+ import { hasVisibleChildren } from '@instructure/ui-a11y-utils'
27
+ import { omitProps, useDeterministicId } from '@instructure/ui-react-utils'
28
+
29
+ import { useStyle } from '@instructure/emotion'
30
+ import { FormFieldMessages } from '../../FormFieldMessages/v2'
31
+ import generateStyle from './styles'
32
+ import { allowedProps } from './props'
33
+ import type { FormFieldLayoutProps } from './props'
34
+
35
+ /**
36
+ ---
37
+ parent: FormField
38
+ ---
39
+ **/
40
+ const FormFieldLayout = forwardRef<Element, FormFieldLayoutProps>(
41
+ (props, ref) => {
42
+ const {
43
+ inline = false,
44
+ layout = 'stacked',
45
+ as = 'label',
46
+ labelAlign = 'end',
47
+ vAlign,
48
+ label,
49
+ messages,
50
+ messagesId: messagesIdProp,
51
+ children,
52
+ width,
53
+ elementRef,
54
+ inputContainerRef,
55
+ isGroup,
56
+ isRequired = false,
57
+ margin,
58
+ disabled = false,
59
+ readOnly = false,
60
+ themeOverride,
61
+ ...rest
62
+ } = props
63
+
64
+ // Deterministic ID generation
65
+ const [deterministicId, setDeterministicId] = useState<string | undefined>()
66
+ const getId = useDeterministicId('FormFieldLayout')
67
+ useEffect(() => {
68
+ setDeterministicId(getId())
69
+ }, [])
70
+
71
+ const messagesId = messagesIdProp || deterministicId
72
+ const labelId = deterministicId ? `${deterministicId}-Label` : undefined
73
+
74
+ // Filter out error and success messages when disabled or readOnly
75
+ const filteredMessages =
76
+ disabled || readOnly
77
+ ? messages?.filter(
78
+ (msg) =>
79
+ msg.type !== 'error' &&
80
+ msg.type !== 'newError' &&
81
+ msg.type !== 'success'
82
+ )
83
+ : messages
84
+
85
+ // Compute style props
86
+ const hasMessages =
87
+ filteredMessages && filteredMessages.length > 0
88
+ ? filteredMessages.some((msg) => {
89
+ if (msg.text) {
90
+ if (typeof msg.text === 'string') {
91
+ return msg.text.length > 0
92
+ }
93
+ return true
94
+ }
95
+ return false
96
+ })
97
+ : false
98
+
99
+ const hasVisibleLabel = label ? hasVisibleChildren(label) : false
100
+
101
+ const hasErrorMsgAndIsGroup =
102
+ !!filteredMessages?.find(
103
+ (m) => m.type === 'error' || m.type === 'newError'
104
+ ) && !!isGroup
105
+
106
+ const invalid = !!filteredMessages?.find(
107
+ (m) => m.type === 'error' || m.type === 'newError'
108
+ )
109
+
110
+ // Styles
111
+ const styles = useStyle({
112
+ generateStyle,
113
+ themeOverride,
114
+ params: {
115
+ hasMessages,
116
+ hasVisibleLabel,
117
+ hasErrorMsgAndIsGroup,
118
+ inline,
119
+ layout,
120
+ vAlign,
121
+ labelAlign,
122
+ margin,
123
+ messages: filteredMessages,
124
+ isRequired,
125
+ invalid
126
+ },
127
+ componentId: 'FormFieldLayout',
128
+ displayName: 'FormFieldLayout'
129
+ })
130
+
131
+ const ElementType = as
132
+
133
+ const handleRef = useCallback(
134
+ (el: Element | null) => {
135
+ if (typeof ref === 'function') {
136
+ ref(el)
137
+ } else if (ref) {
138
+ const refObject = ref as React.MutableRefObject<Element | null>
139
+ refObject.current = el
140
+ }
141
+
142
+ if (typeof elementRef === 'function') {
143
+ elementRef(el)
144
+ }
145
+ },
146
+ [ref, elementRef]
147
+ )
148
+
149
+ const handleInputContainerRef = useCallback(
150
+ (node: HTMLElement | null) => {
151
+ if (typeof inputContainerRef === 'function') {
152
+ inputContainerRef(node)
153
+ }
154
+ },
155
+ [inputContainerRef]
156
+ )
157
+
158
+ const renderLabel = () => {
159
+ const labelContent = hasVisibleLabel ? (
160
+ <>
161
+ {label}
162
+ {isRequired && (
163
+ <span
164
+ css={invalid ? styles?.requiredAsterisk : {}}
165
+ aria-hidden={true}
166
+ >
167
+ {' '}
168
+ *
169
+ </span>
170
+ )}
171
+ </>
172
+ ) : (
173
+ label
174
+ )
175
+
176
+ if (hasVisibleLabel) {
177
+ if (ElementType === 'fieldset') {
178
+ // `legend` has some special built in CSS, this can only be reset
179
+ // this way https://stackoverflow.com/a/65866981/319473
180
+ return (
181
+ <legend style={{ display: 'contents' }}>
182
+ <span css={styles?.formFieldLabel}>{labelContent}</span>
183
+ </legend>
184
+ )
185
+ }
186
+ return <span css={styles?.formFieldLabel}>{labelContent}</span>
187
+ } else if (label) {
188
+ if (ElementType === 'fieldset') {
189
+ return (
190
+ <legend id={labelId} style={{ display: 'contents' }}>
191
+ {label}
192
+ </legend>
193
+ )
194
+ }
195
+ // needs to be wrapped because it needs an `id`
196
+ return (
197
+ <div id={labelId} style={{ display: 'contents' }}>
198
+ {label}
199
+ </div>
200
+ )
201
+ } else return null
202
+ }
203
+
204
+ const renderVisibleMessages = () => {
205
+ return hasMessages ? (
206
+ <FormFieldMessages
207
+ id={messagesId}
208
+ messages={filteredMessages}
209
+ gridArea="messages"
210
+ />
211
+ ) : null
212
+ }
213
+
214
+ return (
215
+ <ElementType
216
+ {...omitProps(rest, [...allowedProps])}
217
+ css={styles?.formFieldLayout}
218
+ aria-describedby={hasMessages ? messagesId : undefined}
219
+ aria-errormessage={rest['aria-invalid'] ? messagesId : undefined}
220
+ style={{ width }}
221
+ ref={handleRef}
222
+ >
223
+ {renderLabel()}
224
+ {hasErrorMsgAndIsGroup && renderVisibleMessages()}
225
+ <span css={styles?.formFieldChildren} ref={handleInputContainerRef}>
226
+ {children}
227
+ </span>
228
+ {!hasErrorMsgAndIsGroup && renderVisibleMessages()}
229
+ </ElementType>
230
+ )
231
+ }
232
+ )
233
+
234
+ FormFieldLayout.displayName = 'FormFieldLayout'
235
+
236
+ export default FormFieldLayout
237
+ export { FormFieldLayout, allowedProps }
@@ -0,0 +1,157 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import type {
26
+ AsElementType,
27
+ OtherHTMLAttributes
28
+ } from '@instructure/shared-types'
29
+ import type {
30
+ ComponentStyle,
31
+ Spacing,
32
+ ThemeOverrideValue
33
+ } from '@instructure/emotion'
34
+ import type { FormMessage } from '../../utils/v1/FormPropTypes'
35
+ import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
36
+
37
+ type FormFieldLayoutOwnProps = {
38
+ label: React.ReactNode
39
+ /**
40
+ * the id of the input (to link it to its label for a11y)
41
+ */
42
+ id?: string
43
+ /**
44
+ * the element type to render as
45
+ */
46
+ as?: AsElementType
47
+ /**
48
+ * Array of objects with shape: `{
49
+ * text: React.ReactNode,
50
+ * type: One of: ['newError', 'error', 'hint', 'success', 'screenreader-only']
51
+ * }`
52
+ */
53
+ messages?: FormMessage[]
54
+ /**
55
+ * id for the form field messages
56
+ */
57
+ messagesId?: string
58
+ children?: React.ReactNode
59
+ /**
60
+ * If `true` use an inline layout -- content will flow on the left/right side
61
+ * of this component
62
+ */
63
+ inline?: boolean
64
+ /**
65
+ * In `stacked` mode the container is below the label, in `inline` mode the
66
+ * container is to the right/left (depending on text direction)
67
+ */
68
+ layout?: 'stacked' | 'inline'
69
+ /**
70
+ * The horizontal alignment of the label. Only works in `inline` layout
71
+ */
72
+ labelAlign?: 'start' | 'end'
73
+ /**
74
+ * The vertical alignment of the label and the controls.
75
+ * "top" by default
76
+ */
77
+ vAlign?: 'top' | 'middle' | 'bottom'
78
+ width?: string
79
+ /**
80
+ * Provides a reference to the container that holds the input element
81
+ * @param element The element that holds the input control as its children
82
+ */
83
+ inputContainerRef?: (element: HTMLElement | null) => void
84
+ /**
85
+ * provides a reference to the underlying html root element
86
+ */
87
+ elementRef?: (element: Element | null) => void
88
+ isGroup?: boolean
89
+ /**
90
+ * If `true`, displays an asterisk after the label to indicate the field is required
91
+ */
92
+ isRequired?: boolean
93
+
94
+ /**
95
+ * Valid values are `0`, `none`, `auto`, and Spacing token values,
96
+ * see https://instructure.design/layout-spacing. Apply these values via
97
+ * familiar CSS-like shorthand. For example, `margin="small auto large"`.
98
+ */
99
+ margin?: Spacing
100
+ /**
101
+ * Whether the field is disabled. When true, error and success messages will be hidden.
102
+ */
103
+ disabled?: boolean
104
+ /**
105
+ * Whether the field is read-only. When true, error and success messages will be hidden.
106
+ */
107
+ readOnly?: boolean
108
+ }
109
+
110
+ type PropKeys = keyof FormFieldLayoutOwnProps
111
+
112
+ type AllowedPropKeys = Readonly<Array<PropKeys>>
113
+
114
+ type FormFieldLayoutProps = FormFieldLayoutOwnProps & {
115
+ themeOverride?: ThemeOverrideValue
116
+ } & OtherHTMLAttributes<FormFieldLayoutOwnProps> &
117
+ WithDeterministicIdProps
118
+
119
+ type FormFieldLayoutStyle = ComponentStyle<
120
+ | 'formFieldLayout'
121
+ | 'formFieldLabel'
122
+ | 'formFieldChildren'
123
+ | 'requiredAsterisk'
124
+ >
125
+ const allowedProps: AllowedPropKeys = [
126
+ 'label',
127
+ 'id',
128
+ 'as',
129
+ 'messages',
130
+ 'messagesId',
131
+ 'children',
132
+ 'inline',
133
+ 'layout',
134
+ 'labelAlign',
135
+ 'width',
136
+ 'inputContainerRef',
137
+ 'elementRef',
138
+ 'margin',
139
+ 'vAlign',
140
+ 'isRequired',
141
+ 'disabled',
142
+ 'readOnly'
143
+ ]
144
+
145
+ type FormFieldStyleProps = {
146
+ hasMessages: boolean
147
+ hasVisibleLabel: boolean
148
+ hasErrorMsgAndIsGroup: boolean
149
+ }
150
+
151
+ export type {
152
+ FormFieldStyleProps,
153
+ FormFieldLayoutProps,
154
+ FormFieldLayoutStyle,
155
+ FormFieldLayoutOwnProps
156
+ }
157
+ export { allowedProps }
@@ -0,0 +1,209 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import type {
26
+ FormFieldLayoutProps,
27
+ FormFieldLayoutStyle,
28
+ FormFieldStyleProps
29
+ } from './props'
30
+ import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes'
31
+ import { calcSpacingFromShorthand } from '@instructure/emotion'
32
+
33
+ type StyleParams = FormFieldStyleProps & {
34
+ inline: FormFieldLayoutProps['inline']
35
+ layout: FormFieldLayoutProps['layout']
36
+ vAlign: FormFieldLayoutProps['vAlign']
37
+ labelAlign: FormFieldLayoutProps['labelAlign']
38
+ margin: FormFieldLayoutProps['margin']
39
+ messages: FormFieldLayoutProps['messages']
40
+ isRequired: FormFieldLayoutProps['isRequired']
41
+ invalid: boolean
42
+ }
43
+
44
+ const generateGridLayout = (
45
+ isInlineLayout: boolean,
46
+ hasErrorMsgAndIsGroup: boolean,
47
+ hasVisibleLabel: boolean,
48
+ hasMessages: boolean
49
+ ) => {
50
+ if (isInlineLayout) {
51
+ if (hasErrorMsgAndIsGroup) {
52
+ if (hasMessages) {
53
+ return `${hasVisibleLabel ? ' "label messages"' : '. messages'}
54
+ ". controls"`
55
+ } else {
56
+ return `${hasVisibleLabel ? ' "label controls"' : '. controls'}`
57
+ }
58
+ } else {
59
+ return `${hasVisibleLabel ? ' "label controls"' : '. controls'}
60
+ ${hasMessages ? ' ". messages"' : ''}`
61
+ }
62
+ }
63
+ // stacked layout -- in this case we could use a simple `Flex`
64
+ if (hasErrorMsgAndIsGroup) {
65
+ return `${hasVisibleLabel ? ' "label"' : ''}
66
+ ${hasMessages ? ' "messages"' : ''}
67
+ "controls"`
68
+ } else {
69
+ return `${hasVisibleLabel ? ' "label"' : ''}
70
+ "controls"
71
+ ${hasMessages ? ' "messages"' : ''}`
72
+ }
73
+ }
74
+ /**
75
+ * ---
76
+ * private: true
77
+ * ---
78
+ * Generates the style object from the theme and provided additional information
79
+ * @param componentTheme The theme variable object.
80
+ * @param params Additional parameters to customize the style.
81
+ * @param sharedTokens Shared token object that stores common values for the theme.
82
+ * @return The final style object, which will be used in the component
83
+ */
84
+ const generateStyle = (
85
+ componentTheme: NewComponentTypes['FormFieldLayout'],
86
+ params: StyleParams,
87
+ sharedTokens: SharedTokens
88
+ ): FormFieldLayoutStyle => {
89
+ const { inline, layout, vAlign, labelAlign, margin, messages } = params
90
+ const { hasMessages, hasVisibleLabel, hasErrorMsgAndIsGroup } = params
91
+ const cssMargin = calcSpacingFromShorthand(margin, {
92
+ ...sharedTokens.spacing,
93
+ ...sharedTokens.legacy.spacing
94
+ })
95
+ const isInlineLayout = layout === 'inline'
96
+
97
+ const hasNonEmptyMessages = messages?.reduce(
98
+ (acc, message) => acc || message.type !== 'screenreader-only',
99
+ false
100
+ )
101
+
102
+ // This is quite ugly, we should simplify it
103
+ const gridTemplateAreas = generateGridLayout(
104
+ isInlineLayout,
105
+ hasErrorMsgAndIsGroup,
106
+ hasVisibleLabel,
107
+ hasMessages
108
+ )
109
+ let gridTemplateColumns = '100%' // stacked layout
110
+ if (isInlineLayout) {
111
+ gridTemplateColumns = '1fr 3fr'
112
+ if (inline) {
113
+ gridTemplateColumns = 'auto 3fr'
114
+ }
115
+ }
116
+ const labelStyles = {
117
+ all: 'initial',
118
+ display: 'block',
119
+ gridArea: 'label',
120
+ color: componentTheme.textColor,
121
+ fontFamily: componentTheme.fontFamily,
122
+ fontWeight: componentTheme.fontWeight,
123
+ fontSize: componentTheme.fontSize,
124
+ lineHeight: componentTheme.lineHeight,
125
+ ...(isInlineLayout && {
126
+ margin: '0',
127
+ // when inline add a small padding between the label and the control
128
+ paddingRight: componentTheme.gapPrimitives,
129
+ // and use the horizontal alignment prop
130
+ [`@media screen and (width >= ${componentTheme.stackedOrInlineBreakpoint})`]:
131
+ {
132
+ textAlign: labelAlign
133
+ }
134
+ })
135
+ }
136
+
137
+ let alignItems = 'start'
138
+ if (vAlign == 'top') {
139
+ alignItems = 'start'
140
+ } else if (vAlign == 'middle') {
141
+ alignItems = 'center'
142
+ } else if (vAlign == 'bottom') {
143
+ alignItems = 'end'
144
+ }
145
+ return {
146
+ formFieldLayout: {
147
+ label: 'formFieldLayout',
148
+ all: 'initial',
149
+ border: '0',
150
+ padding: '0',
151
+ margin: cssMargin,
152
+ minWidth: '0',
153
+ direction: 'inherit',
154
+ textAlign: 'start',
155
+ opacity: 'inherit',
156
+ display: 'grid',
157
+ alignItems: alignItems,
158
+ verticalAlign: 'middle', // removes margin in inline layouts
159
+ gridTemplateColumns: gridTemplateColumns,
160
+ gridTemplateAreas: gridTemplateAreas,
161
+ [`@media screen and (width < ${componentTheme.stackedOrInlineBreakpoint})`]:
162
+ {
163
+ // for small screens use the stacked layout
164
+ gridTemplateColumns: '100%',
165
+ gridTemplateAreas: generateGridLayout(
166
+ false,
167
+ hasErrorMsgAndIsGroup,
168
+ hasVisibleLabel,
169
+ hasMessages
170
+ )
171
+ },
172
+ columnGap: '0.375rem',
173
+ rowGap: hasNonEmptyMessages ? componentTheme.gapPrimitives : '0',
174
+ width: '100%',
175
+ ...(inline && {
176
+ display: 'inline-grid',
177
+ width: 'auto'
178
+ })
179
+ },
180
+ formFieldLabel: {
181
+ label: 'formFieldLayout__label',
182
+ ...labelStyles,
183
+ // NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
184
+ '&:is(label)': labelStyles,
185
+ '&:-webkit-any(label)': labelStyles,
186
+
187
+ paddingBottom: hasNonEmptyMessages ? '0' : componentTheme.gapPrimitives
188
+ },
189
+ formFieldChildren: {
190
+ label: 'formFieldLayout__children',
191
+ gridArea: 'controls',
192
+ // add a small margin between the message and the controls
193
+ ...(hasMessages && hasErrorMsgAndIsGroup && { marginTop: '0.375rem' }),
194
+ ...(isInlineLayout &&
195
+ inline && {
196
+ [`@media screen and (width >= ${componentTheme.stackedOrInlineBreakpoint})`]:
197
+ {
198
+ justifySelf: 'start'
199
+ }
200
+ })
201
+ },
202
+ requiredAsterisk: {
203
+ label: 'formFieldLayout__requiredAsterisk',
204
+ color: componentTheme.asteriskColor
205
+ }
206
+ }
207
+ }
208
+
209
+ export default generateStyle
@@ -28,7 +28,7 @@ import { ScreenReaderContent } from '@instructure/ui-a11y-content'
28
28
 
29
29
  import { IconWarningSolid } from '@instructure/ui-icons'
30
30
 
31
- import { withStyle } from '@instructure/emotion'
31
+ import { withStyleLegacy as withStyle } from '@instructure/emotion'
32
32
 
33
33
  import generateStyle from './styles'
34
34
  import generateComponentTheme from './theme'
@@ -24,7 +24,10 @@
24
24
 
25
25
  import type { FormFieldMessageTheme } from '@instructure/shared-types'
26
26
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
27
- import type { FormMessageType, FormMessageChild } from '../FormPropTypes'
27
+ import type {
28
+ FormMessageType,
29
+ FormMessageChild
30
+ } from '../../utils/v1/FormPropTypes'
28
31
 
29
32
  type FormFieldMessageOwnProps = {
30
33
  variant?: FormMessageType
@@ -24,8 +24,7 @@
24
24
 
25
25
  import type { FormFieldMessageTheme } from '@instructure/shared-types'
26
26
  import type { FormFieldMessageProps, FormFieldMessageStyle } from './props'
27
- import type { FormMessageType } from '../FormPropTypes'
28
-
27
+ import type { FormMessageType } from '../../utils/v1/FormPropTypes'
29
28
  /**
30
29
  * ---
31
30
  * private: true
@@ -54,7 +53,7 @@ const generateStyle = (
54
53
  errorIcon: {
55
54
  fontSize: componentTheme.fontSize,
56
55
  marginRight: componentTheme.errorIconMarginRight,
57
- lineHeight: 1.25,
56
+ lineHeight: 1.25
58
57
  },
59
58
  formFieldMessage: {
60
59
  label: 'formFieldMessage',