@strictly/react-form 0.0.1

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 (239) hide show
  1. package/.eslintrc.cjs +26 -0
  2. package/.out/.storybook/main.d.ts +3 -0
  3. package/.out/.storybook/main.js +32 -0
  4. package/.out/.storybook/preview.d.ts +4 -0
  5. package/.out/.storybook/preview.js +20 -0
  6. package/.out/.vitest/install_deterministic_random.d.ts +2 -0
  7. package/.out/.vitest/install_deterministic_random.js +15 -0
  8. package/.out/.vitest/install_storybook_preview.d.ts +1 -0
  9. package/.out/.vitest/install_storybook_preview.js +7 -0
  10. package/.out/.vitest/match_media.d.ts +1 -0
  11. package/.out/.vitest/match_media.js +5 -0
  12. package/.out/.vitest/resize_observer.d.ts +1 -0
  13. package/.out/.vitest/resize_observer.js +4 -0
  14. package/.out/core/mobx/field_adapter.d.ts +9 -0
  15. package/.out/core/mobx/field_adapter.js +1 -0
  16. package/.out/core/mobx/field_adapter_builder.d.ts +22 -0
  17. package/.out/core/mobx/field_adapter_builder.js +56 -0
  18. package/.out/core/mobx/flattened_adapters_of_fields.d.ts +9 -0
  19. package/.out/core/mobx/flattened_adapters_of_fields.js +1 -0
  20. package/.out/core/mobx/flattened_list_type_defs_of.d.ts +8 -0
  21. package/.out/core/mobx/flattened_list_type_defs_of.js +1 -0
  22. package/.out/core/mobx/form_presenter.d.ts +61 -0
  23. package/.out/core/mobx/form_presenter.js +425 -0
  24. package/.out/core/mobx/specs/flattened_adapters_of_fields.tests.d.ts +1 -0
  25. package/.out/core/mobx/specs/flattened_adapters_of_fields.tests.js +13 -0
  26. package/.out/core/mobx/specs/flattened_list_type_defs_of.tests.d.ts +1 -0
  27. package/.out/core/mobx/specs/flattened_list_type_defs_of.tests.js +16 -0
  28. package/.out/core/mobx/specs/form_presenter.tests.d.ts +1 -0
  29. package/.out/core/mobx/specs/form_presenter.tests.js +697 -0
  30. package/.out/core/mobx/types.d.ts +19 -0
  31. package/.out/core/mobx/types.js +1 -0
  32. package/.out/core/props.d.ts +12 -0
  33. package/.out/core/props.js +1 -0
  34. package/.out/field_converters/chain_field_converter.d.ts +3 -0
  35. package/.out/field_converters/chain_field_converter.js +46 -0
  36. package/.out/field_converters/identity_converter.d.ts +3 -0
  37. package/.out/field_converters/identity_converter.js +14 -0
  38. package/.out/field_converters/integer_to_string_converter.d.ts +7 -0
  39. package/.out/field_converters/integer_to_string_converter.js +26 -0
  40. package/.out/field_converters/list_converter.d.ts +2 -0
  41. package/.out/field_converters/list_converter.js +8 -0
  42. package/.out/field_converters/maybe_identity_converter.d.ts +8 -0
  43. package/.out/field_converters/maybe_identity_converter.js +15 -0
  44. package/.out/field_converters/nullable_to_boolean_converter.d.ts +11 -0
  45. package/.out/field_converters/nullable_to_boolean_converter.js +31 -0
  46. package/.out/field_converters/select_value_type_converter.d.ts +23 -0
  47. package/.out/field_converters/select_value_type_converter.js +60 -0
  48. package/.out/field_converters/trimming_string_converter.d.ts +6 -0
  49. package/.out/field_converters/trimming_string_converter.js +14 -0
  50. package/.out/field_converters/validating_converter.d.ts +3 -0
  51. package/.out/field_converters/validating_converter.js +21 -0
  52. package/.out/field_validators/minimum_string_length_field_validator.d.ts +2 -0
  53. package/.out/field_validators/minimum_string_length_field_validator.js +8 -0
  54. package/.out/field_value_factories/prototyping_field_value_factory.d.ts +2 -0
  55. package/.out/field_value_factories/prototyping_field_value_factory.js +5 -0
  56. package/.out/index.d.ts +16 -0
  57. package/.out/index.js +16 -0
  58. package/.out/mantine/create_checkbox.d.ts +9 -0
  59. package/.out/mantine/create_checkbox.js +37 -0
  60. package/.out/mantine/create_list.d.ts +15 -0
  61. package/.out/mantine/create_list.js +16 -0
  62. package/.out/mantine/create_pill.d.ts +7 -0
  63. package/.out/mantine/create_pill.js +15 -0
  64. package/.out/mantine/create_radio.d.ts +8 -0
  65. package/.out/mantine/create_radio.js +10 -0
  66. package/.out/mantine/create_radio_group.d.ts +9 -0
  67. package/.out/mantine/create_radio_group.js +34 -0
  68. package/.out/mantine/create_text_input.d.ts +19 -0
  69. package/.out/mantine/create_text_input.js +38 -0
  70. package/.out/mantine/create_value_input.d.ts +17 -0
  71. package/.out/mantine/create_value_input.js +38 -0
  72. package/.out/mantine/hooks.d.ts +56 -0
  73. package/.out/mantine/hooks.js +135 -0
  74. package/.out/mantine/specs/checkbox_constants.d.ts +1 -0
  75. package/.out/mantine/specs/checkbox_constants.js +1 -0
  76. package/.out/mantine/specs/checkbox_hooks.stories.d.ts +13 -0
  77. package/.out/mantine/specs/checkbox_hooks.stories.js +63 -0
  78. package/.out/mantine/specs/checkbox_hooks.tests.d.ts +1 -0
  79. package/.out/mantine/specs/checkbox_hooks.tests.js +74 -0
  80. package/.out/mantine/specs/list_hooks.stories.d.ts +11 -0
  81. package/.out/mantine/specs/list_hooks.stories.js +48 -0
  82. package/.out/mantine/specs/list_hooks.tests.d.ts +1 -0
  83. package/.out/mantine/specs/list_hooks.tests.js +12 -0
  84. package/.out/mantine/specs/radio_group_constants.d.ts +4 -0
  85. package/.out/mantine/specs/radio_group_constants.js +11 -0
  86. package/.out/mantine/specs/radio_group_hooks.stories.d.ts +14 -0
  87. package/.out/mantine/specs/radio_group_hooks.stories.js +68 -0
  88. package/.out/mantine/specs/radio_group_hooks.tests.d.ts +1 -0
  89. package/.out/mantine/specs/radio_group_hooks.tests.js +62 -0
  90. package/.out/mantine/specs/select_hooks.stories.d.ts +12 -0
  91. package/.out/mantine/specs/select_hooks.stories.js +57 -0
  92. package/.out/mantine/specs/select_hooks.tests.d.ts +1 -0
  93. package/.out/mantine/specs/select_hooks.tests.js +12 -0
  94. package/.out/mantine/specs/select_hooks_constant.d.ts +1 -0
  95. package/.out/mantine/specs/select_hooks_constant.js +1 -0
  96. package/.out/mantine/specs/text_input_constants.d.ts +1 -0
  97. package/.out/mantine/specs/text_input_constants.js +1 -0
  98. package/.out/mantine/specs/text_input_hooks.stories.d.ts +21 -0
  99. package/.out/mantine/specs/text_input_hooks.stories.js +88 -0
  100. package/.out/mantine/specs/text_input_hooks.tests.d.ts +1 -0
  101. package/.out/mantine/specs/text_input_hooks.tests.js +79 -0
  102. package/.out/mantine/specs/value_input_constants.d.ts +2 -0
  103. package/.out/mantine/specs/value_input_constants.js +2 -0
  104. package/.out/mantine/specs/value_input_hooks.stories.d.ts +23 -0
  105. package/.out/mantine/specs/value_input_hooks.stories.js +124 -0
  106. package/.out/mantine/specs/value_input_hooks.tests.d.ts +1 -0
  107. package/.out/mantine/specs/value_input_hooks.tests.js +12 -0
  108. package/.out/mantine/types.d.ts +11 -0
  109. package/.out/mantine/types.js +1 -0
  110. package/.out/tsconfig.json +27 -0
  111. package/.out/tsconfig.tsbuildinfo +1 -0
  112. package/.out/tsup.config.d.ts +3 -0
  113. package/.out/tsup.config.js +12 -0
  114. package/.out/types/all_fields_of_fields.d.ts +5 -0
  115. package/.out/types/all_fields_of_fields.js +1 -0
  116. package/.out/types/boolean_fields_of_fields.d.ts +5 -0
  117. package/.out/types/boolean_fields_of_fields.js +1 -0
  118. package/.out/types/error_type_of_field.d.ts +2 -0
  119. package/.out/types/error_type_of_field.js +1 -0
  120. package/.out/types/field.d.ts +7 -0
  121. package/.out/types/field.js +1 -0
  122. package/.out/types/field_converters.d.ts +29 -0
  123. package/.out/types/field_converters.js +5 -0
  124. package/.out/types/field_validator.d.ts +3 -0
  125. package/.out/types/field_validator.js +1 -0
  126. package/.out/types/flattened_form_fields_of.d.ts +9 -0
  127. package/.out/types/flattened_form_fields_of.js +1 -0
  128. package/.out/types/list_fields_of_fields.d.ts +5 -0
  129. package/.out/types/list_fields_of_fields.js +1 -0
  130. package/.out/types/specs/boolean_fields_of_fields.tests.d.ts +1 -0
  131. package/.out/types/specs/boolean_fields_of_fields.tests.js +11 -0
  132. package/.out/types/specs/error_type_of_field.tests.d.ts +1 -0
  133. package/.out/types/specs/error_type_of_field.tests.js +7 -0
  134. package/.out/types/specs/flattened_form_fields_of.tests.d.ts +1 -0
  135. package/.out/types/specs/flattened_form_fields_of.tests.js +13 -0
  136. package/.out/types/specs/string_fields_of_fields.tests.d.ts +1 -0
  137. package/.out/types/specs/string_fields_of_fields.tests.js +19 -0
  138. package/.out/types/specs/value_type_of_field.tests.d.ts +1 -0
  139. package/.out/types/specs/value_type_of_field.tests.js +7 -0
  140. package/.out/types/string_fields_of_fields.d.ts +5 -0
  141. package/.out/types/string_fields_of_fields.js +1 -0
  142. package/.out/types/value_type_of_field.d.ts +2 -0
  143. package/.out/types/value_type_of_field.js +1 -0
  144. package/.out/util/partial.d.ts +11 -0
  145. package/.out/util/partial.js +74 -0
  146. package/.out/vitest.workspace.d.ts +2 -0
  147. package/.out/vitest.workspace.js +22 -0
  148. package/.storybook/main.ts +40 -0
  149. package/.storybook/preview.tsx +28 -0
  150. package/.storybook/vite.config.mts +38 -0
  151. package/.turbo/turbo-build.log +18 -0
  152. package/.turbo/turbo-check-types.log +3 -0
  153. package/.turbo/turbo-release$colon$exports.log +3 -0
  154. package/.vitest/install_deterministic_random.ts +17 -0
  155. package/.vitest/install_storybook_preview.ts +9 -0
  156. package/.vitest/match_media.ts +7 -0
  157. package/.vitest/resize_observer.ts +5 -0
  158. package/README.md +2 -0
  159. package/core/mobx/field_adapter.ts +32 -0
  160. package/core/mobx/field_adapter_builder.ts +313 -0
  161. package/core/mobx/flattened_adapters_of_fields.ts +35 -0
  162. package/core/mobx/flattened_list_type_defs_of.ts +17 -0
  163. package/core/mobx/form_presenter.ts +705 -0
  164. package/core/mobx/specs/flattened_adapters_of_fields.tests.ts +72 -0
  165. package/core/mobx/specs/flattened_list_type_defs_of.tests.ts +35 -0
  166. package/core/mobx/specs/form_presenter.tests.ts +989 -0
  167. package/core/mobx/types.ts +54 -0
  168. package/core/props.ts +21 -0
  169. package/dist/index.cjs +11479 -0
  170. package/dist/index.d.cts +345 -0
  171. package/dist/index.d.ts +345 -0
  172. package/dist/index.js +11486 -0
  173. package/field_converters/chain_field_converter.ts +74 -0
  174. package/field_converters/identity_converter.ts +39 -0
  175. package/field_converters/integer_to_string_converter.ts +32 -0
  176. package/field_converters/list_converter.ts +15 -0
  177. package/field_converters/maybe_identity_converter.ts +23 -0
  178. package/field_converters/nullable_to_boolean_converter.ts +56 -0
  179. package/field_converters/select_value_type_converter.ts +141 -0
  180. package/field_converters/trimming_string_converter.ts +23 -0
  181. package/field_converters/validating_converter.ts +35 -0
  182. package/field_validators/minimum_string_length_field_validator.ts +13 -0
  183. package/field_value_factories/prototyping_field_value_factory.ts +11 -0
  184. package/index.ts +16 -0
  185. package/mantine/create_checkbox.tsx +79 -0
  186. package/mantine/create_list.tsx +58 -0
  187. package/mantine/create_pill.tsx +43 -0
  188. package/mantine/create_radio.tsx +36 -0
  189. package/mantine/create_radio_group.tsx +71 -0
  190. package/mantine/create_text_input.tsx +80 -0
  191. package/mantine/create_value_input.tsx +81 -0
  192. package/mantine/hooks.tsx +394 -0
  193. package/mantine/specs/__snapshots__/check_box_hooks.tests.tsx.snap +227 -0
  194. package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +227 -0
  195. package/mantine/specs/__snapshots__/list_hooks.tests.tsx.snap +68 -0
  196. package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +695 -0
  197. package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +225 -0
  198. package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +202 -0
  199. package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +613 -0
  200. package/mantine/specs/checkbox_constants.ts +1 -0
  201. package/mantine/specs/checkbox_hooks.stories.tsx +79 -0
  202. package/mantine/specs/checkbox_hooks.tests.tsx +100 -0
  203. package/mantine/specs/list_hooks.stories.tsx +83 -0
  204. package/mantine/specs/list_hooks.tests.tsx +15 -0
  205. package/mantine/specs/radio_group_constants.ts +12 -0
  206. package/mantine/specs/radio_group_hooks.stories.tsx +103 -0
  207. package/mantine/specs/radio_group_hooks.tests.tsx +92 -0
  208. package/mantine/specs/select_hooks.stories.tsx +77 -0
  209. package/mantine/specs/select_hooks.tests.tsx +14 -0
  210. package/mantine/specs/select_hooks_constant.ts +1 -0
  211. package/mantine/specs/text_input_constants.ts +1 -0
  212. package/mantine/specs/text_input_hooks.stories.tsx +124 -0
  213. package/mantine/specs/text_input_hooks.tests.tsx +106 -0
  214. package/mantine/specs/value_input_constants.ts +2 -0
  215. package/mantine/specs/value_input_hooks.stories.tsx +182 -0
  216. package/mantine/specs/value_input_hooks.tests.tsx +14 -0
  217. package/mantine/types.ts +13 -0
  218. package/package.exports.json +18 -0
  219. package/package.json +74 -0
  220. package/tsconfig.build.json +13 -0
  221. package/tsconfig.json +27 -0
  222. package/tsup.config.ts +16 -0
  223. package/types/all_fields_of_fields.ts +9 -0
  224. package/types/boolean_fields_of_fields.ts +8 -0
  225. package/types/error_type_of_field.ts +3 -0
  226. package/types/field.ts +9 -0
  227. package/types/field_converters.ts +64 -0
  228. package/types/field_validator.ts +7 -0
  229. package/types/flattened_form_fields_of.ts +16 -0
  230. package/types/list_fields_of_fields.ts +7 -0
  231. package/types/specs/boolean_fields_of_fields.tests.ts +23 -0
  232. package/types/specs/error_type_of_field.tests.ts +10 -0
  233. package/types/specs/flattened_form_fields_of.tests.ts +43 -0
  234. package/types/specs/string_fields_of_fields.tests.ts +40 -0
  235. package/types/specs/value_type_of_field.tests.ts +10 -0
  236. package/types/string_fields_of_fields.ts +6 -0
  237. package/types/value_type_of_field.ts +3 -0
  238. package/util/partial.tsx +200 -0
  239. package/vitest.workspace.ts +26 -0
@@ -0,0 +1,40 @@
1
+ import { type Field } from 'types/field'
2
+ import { type StringFieldsOfFields } from 'types/string_fields_of_fields'
3
+
4
+ describe('StringFieldsOfFields', function () {
5
+ describe('filtering', function () {
6
+ const e1 = Symbol()
7
+ const e2 = Symbol()
8
+ const e3 = Symbol()
9
+ type E1 = typeof e1
10
+ type E2 = typeof e2
11
+ type E3 = typeof e3
12
+ type F = {
13
+ b: Field<boolean, E1>,
14
+ s: Field<string, E2>,
15
+ n: Field<number, E3>,
16
+ }
17
+
18
+ it('equals expected type', function () {
19
+ expectTypeOf<StringFieldsOfFields<F>>().toEqualTypeOf<{
20
+ s: Field<string, E2>,
21
+ }>()
22
+ })
23
+ })
24
+
25
+ describe('string union with null', function () {
26
+ const e = Symbol()
27
+ type E = typeof e
28
+ type F = {
29
+ s: Field<'a' | 'b' | 'c' | null | undefined, E>,
30
+ }
31
+
32
+ describe('StringFieldsOfFields', function () {
33
+ it('equals expected type', function () {
34
+ expectTypeOf<StringFieldsOfFields<F>>().toEqualTypeOf<{
35
+ s: Field<'a' | 'b' | 'c' | null | undefined, E>,
36
+ }>()
37
+ })
38
+ })
39
+ })
40
+ })
@@ -0,0 +1,10 @@
1
+ import { type Field } from 'types/field'
2
+ import { type ValueTypeOfField } from 'types/value_type_of_field'
3
+
4
+ describe('ValueTypeOfField', function () {
5
+ it('equals expected type', function () {
6
+ const v = Symbol()
7
+ type V = typeof v
8
+ expectTypeOf<ValueTypeOfField<Field<V, unknown>>>().toEqualTypeOf<V>()
9
+ })
10
+ })
@@ -0,0 +1,6 @@
1
+ import { type Fields } from './field'
2
+ import { type ValueTypeOfField } from './value_type_of_field'
3
+
4
+ export type StringFieldsOfFields<F extends Fields> = {
5
+ [K in keyof F as ValueTypeOfField<F[K]> extends string | undefined | null ? K : never]: F[K]
6
+ }
@@ -0,0 +1,3 @@
1
+ import { type Field } from './field'
2
+
3
+ export type ValueTypeOfField<F extends Field> = F extends Field<infer V> ? V : never
@@ -0,0 +1,200 @@
1
+ import { observer } from 'mobx-react'
2
+ import {
3
+ type ComponentProps,
4
+ type ComponentType,
5
+ type DependencyList,
6
+ type ForwardedRef,
7
+ forwardRef,
8
+ type ForwardRefExoticComponent,
9
+ type PropsWithoutRef,
10
+ useMemo,
11
+ } from 'react'
12
+
13
+ export type PartialComponent<
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ Component extends ComponentType<any>,
16
+ CurriedProps,
17
+ AdditionalProps = {},
18
+ > = Exclude<keyof CurriedProps, keyof ComponentProps<Component>> extends never
19
+ ? UnsafePartialComponent<Component, CurriedProps, AdditionalProps>
20
+ : keyof CurriedProps extends (string | number)
21
+ ? `unmatched prop: ${Exclude<keyof CurriedProps, keyof ComponentProps<Component>>}`
22
+ : Exclude<keyof CurriedProps, keyof ComponentProps<Component>>
23
+
24
+ export type UnsafePartialComponent<
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ Component extends ComponentType<any>,
27
+ CurriedProps,
28
+ AdditionalProps = {},
29
+ > = ForwardRefExoticComponent<
30
+ PropsWithoutRef<RemainingComponentProps<Component, CurriedProps> & AdditionalProps>
31
+ >
32
+
33
+ export function createSimplePartialComponent<
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ Component extends ComponentType<any>,
36
+ CurriedProps extends Partial<ComponentProps<Component>>,
37
+ >(
38
+ Component: Component,
39
+ curriedProps: CurriedProps,
40
+ ): PartialComponent<Component, CurriedProps> {
41
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
42
+ return forwardRef(
43
+ function (
44
+ exposedProps: PropsWithoutRef<RemainingComponentProps<Component, CurriedProps>>,
45
+ ref: ForwardedRef<typeof Component>,
46
+ ) {
47
+ // forward ref types are really difficult to work with
48
+ // still needs a cast as `extends ComponentType<any>` != `ComponentType<any>`
49
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion
50
+ const C = Component as ComponentType<any>
51
+
52
+ return (
53
+ <C
54
+ ref={ref}
55
+ {...curriedProps}
56
+ {...exposedProps}
57
+ />
58
+ )
59
+ },
60
+ ) as PartialComponent<Component, CurriedProps>
61
+ }
62
+
63
+ export function createPartialComponent<
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ Component extends ComponentType<any>,
66
+ CurriedProps extends Partial<ComponentProps<Component>>,
67
+ AdditionalProps = {},
68
+ >(
69
+ Component: Component,
70
+ curriedPropsSource: (additionalProps: AdditionalProps) => CurriedProps,
71
+ ): PartialComponent<Component, CurriedProps, AdditionalProps> {
72
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
73
+ return forwardRef(
74
+ function (
75
+ exposedProps: PropsWithoutRef<RemainingComponentProps<Component, CurriedProps> & AdditionalProps>,
76
+ ref: ForwardedRef<typeof Component>,
77
+ ) {
78
+ // forward ref types are really difficult to work with
79
+ // still needs a cast as `extends ComponentType<any>` != `ComponentType<any>`
80
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion
81
+ const C = Component as ComponentType<any>
82
+ // TODO is there any way we can memoize this transformation?
83
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
84
+ const curriedProps = curriedPropsSource(exposedProps as AdditionalProps)
85
+
86
+ return (
87
+ <C
88
+ ref={ref}
89
+ {...curriedProps}
90
+ {...exposedProps}
91
+ />
92
+ )
93
+ },
94
+ ) as PartialComponent<Component, CurriedProps, AdditionalProps>
95
+ }
96
+
97
+ export function usePartialComponent<
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ Component extends ComponentType<any>,
100
+ CurriedProps extends Partial<ComponentProps<Component>>,
101
+ AdditionalProps = {},
102
+ >(
103
+ // has to be first so eslint react-hooks/exhaustive-deps can find the callback
104
+ // has to be a function so eslint react-hooks/exhaustive-deps can reason about it :(
105
+ createCurriedProps: (additionalProps: AdditionalProps) => CurriedProps,
106
+ // has to be next so eslint react-hooks/exhaustive-deps can find the deps
107
+ deps: DependencyList,
108
+ Component: Component,
109
+ ): PartialComponent<Component, CurriedProps, AdditionalProps> {
110
+ return useMemo(
111
+ function () {
112
+ return createPartialComponent<Component, CurriedProps, AdditionalProps>(Component, createCurriedProps)
113
+ },
114
+ // eslint-disable-next-line react-hooks/exhaustive-deps
115
+ [
116
+ // eslint-disable-next-line react-hooks/exhaustive-deps
117
+ ...deps,
118
+ Component,
119
+ ],
120
+ )
121
+ }
122
+
123
+ export function createPartialObserverComponent<
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ Component extends ComponentType<any>,
126
+ CurriedProps extends Partial<ComponentProps<Component>>,
127
+ AdditionalProps = {},
128
+ >(
129
+ Component: Component,
130
+ curriedPropsSource: (additionalProps: AdditionalProps) => CurriedProps,
131
+ ): PartialComponent<Component, CurriedProps, AdditionalProps> {
132
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
133
+ return createUnsafePartialObserverComponent(Component, curriedPropsSource) as PartialComponent<Component,
134
+ CurriedProps, AdditionalProps>
135
+ }
136
+
137
+ export function createUnsafePartialObserverComponent<
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ Component extends ComponentType<any>,
140
+ CurriedProps,
141
+ AdditionalProps = {},
142
+ >(
143
+ Component: Component,
144
+ curriedPropsSource: (additionalProps: AdditionalProps) => CurriedProps,
145
+ ): UnsafePartialComponent<Component, CurriedProps, AdditionalProps> {
146
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
147
+ return observer(
148
+ forwardRef(
149
+ function (
150
+ exposedProps: PropsWithoutRef<RemainingComponentProps<Component, CurriedProps> & AdditionalProps>,
151
+ ref: ForwardedRef<typeof Component>,
152
+ ) {
153
+ // forward ref types are really difficult to work with
154
+ // still needs a cast as `extends ComponentType<any>` != `ComponentType<any>`
155
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion
156
+ const C = Component as ComponentType<any>
157
+ // TODO is there any way we can memoize this transformation?
158
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
159
+ const curriedProps = curriedPropsSource(exposedProps as AdditionalProps)
160
+
161
+ return (
162
+ <C
163
+ ref={ref}
164
+ {...curriedProps}
165
+ {...exposedProps}
166
+ />
167
+ )
168
+ },
169
+ ),
170
+ ) as UnsafePartialComponent<Component, CurriedProps, AdditionalProps>
171
+ }
172
+
173
+ export function usePartialObserverComponent<
174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
175
+ Component extends ComponentType<any>,
176
+ CurriedProps extends Partial<ComponentProps<Component>>,
177
+ AdditionalProps = {},
178
+ >(
179
+ // has to be first so eslint react-hooks/exhaustive-deps can find the callback
180
+ curriedPropsSource: (additionalProps: AdditionalProps) => CurriedProps,
181
+ // has to be next so eslint react-hooks/exhaustive-deps can find the deps
182
+ deps: DependencyList,
183
+ Component: Component,
184
+ ) {
185
+ return useMemo(
186
+ function () {
187
+ return createPartialObserverComponent(Component, curriedPropsSource)
188
+ },
189
+ // eslint-disable-next-line react-hooks/exhaustive-deps
190
+ [
191
+ // eslint-disable-next-line react-hooks/exhaustive-deps
192
+ ...deps,
193
+ Component,
194
+ ],
195
+ )
196
+ }
197
+
198
+ type RemainingComponentProps<Component extends ComponentType, CurriedProps> =
199
+ & Omit<ComponentProps<Component>, keyof CurriedProps>
200
+ & JSX.IntrinsicAttributes
@@ -0,0 +1,26 @@
1
+ import { createVitestUserConfig } from '@strictly/support-vite'
2
+ import {
3
+ defineWorkspace,
4
+ } from 'vitest/config'
5
+
6
+ import tsconfig from './tsconfig.json'
7
+
8
+ const config = createVitestUserConfig(tsconfig)
9
+ export default defineWorkspace([
10
+ '.',
11
+ {
12
+ ...config,
13
+ extends: './.storybook/vite.config.mts',
14
+ test: {
15
+ ...(config.test || {}),
16
+ environment: 'jsdom',
17
+ setupFiles: [
18
+ './.vitest/install_deterministic_random.ts',
19
+ // install storybook setup for unit tests that import stories directly
20
+ './.vitest/install_storybook_preview.ts',
21
+ './.vitest/match_media.ts',
22
+ './.vitest/resize_observer.ts',
23
+ ],
24
+ },
25
+ },
26
+ ] as const)