@dev-fastn-ai/react-core 2.4.4 → 2.4.6

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.
package/CHANGELOG.md CHANGED
@@ -5,13 +5,6 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
9
-
10
- ### Added
11
- - `useFieldOptions` hook now supports passing context data to `getOptions` and `loadMore` methods
12
- - Context parameter allows passing form data or additional parameters for dynamic option filtering
13
- - Support for cascading dropdowns and context-dependent option loading
14
-
15
8
  ## [1.0.0] - 2024-01-XX
16
9
 
17
10
  ### Added
package/README.md CHANGED
@@ -603,7 +603,8 @@ For fields of type `select` or `multi-select`, use the `useFieldOptions` hook to
603
603
  ```tsx
604
604
  import { useFieldOptions } from "@fastn-ai/react-core";
605
605
 
606
- function SelectField({ field, value, onChange, isMulti = false }) {
606
+ function SelectField({ field, value, onChange, isMulti = false, context = {} }) {
607
+ // context contains all form values and is used to fetch dependent options
607
608
  const {
608
609
  options,
609
610
  loading,
@@ -613,7 +614,7 @@ function SelectField({ field, value, onChange, isMulti = false }) {
613
614
  error,
614
615
  search,
615
616
  totalLoadedOptions,
616
- } = useFieldOptions(field,context);
617
+ } = useFieldOptions(field, context);
617
618
 
618
619
  function handleInputChange(e) {
619
620
  search(e.target.value);
@@ -715,10 +716,10 @@ function SelectField({ field, value, onChange, isMulti = false }) {
715
716
 
716
717
  ### **Google Drive Picker Fields**
717
718
 
718
- For Google Drive file picker fields, handle the file selection flow. These fields also work with `{ label, value }` objects:
719
+ For Google Drive file picker fields, handle the file selection flow. These fields also work with `{ label, value }` objects and support file type filtering:
719
720
 
720
721
  ```tsx
721
- function GoogleFilesPickerField({ field, value, onChange, isMulti = false }) {
722
+ function GoogleFilesPickerField({ field, value, onChange, isMulti = false, context = {} }) {
722
723
  async function handlePickFiles() {
723
724
  if (field.optionsSource?.openGoogleFilesPicker) {
724
725
  await field.optionsSource.openGoogleFilesPicker({
@@ -743,6 +744,7 @@ function GoogleFilesPickerField({ field, value, onChange, isMulti = false }) {
743
744
  console.error("Google Files Picker error:", pickerError);
744
745
  alert("Failed to pick files: " + pickerError);
745
746
  },
747
+ fileTypes: field?.optionsSource?.fileTypes,
746
748
  });
747
749
  }
748
750
  }
@@ -786,7 +788,7 @@ function GoogleFilesPickerField({ field, value, onChange, isMulti = false }) {
786
788
  Create a reusable component that handles different field types with proper value handling:
787
789
 
788
790
  ```tsx
789
- function FormField({ field, value, onChange }) {
791
+ function FormField({ field, value, onChange, context = {} }) {
790
792
  switch (field.type) {
791
793
  case "text":
792
794
  case "email":
@@ -839,6 +841,7 @@ function FormField({ field, value, onChange }) {
839
841
  value={value}
840
842
  onChange={onChange}
841
843
  isMulti={false}
844
+ context={context}
842
845
  />
843
846
  );
844
847
 
@@ -849,6 +852,7 @@ function FormField({ field, value, onChange }) {
849
852
  value={value}
850
853
  onChange={onChange}
851
854
  isMulti={true}
855
+ context={context}
852
856
  />
853
857
  );
854
858
 
@@ -859,6 +863,7 @@ function FormField({ field, value, onChange }) {
859
863
  value={value}
860
864
  onChange={onChange}
861
865
  isMulti={false}
866
+ context={context}
862
867
  />
863
868
  );
864
869
 
@@ -869,6 +874,7 @@ function FormField({ field, value, onChange }) {
869
874
  value={value}
870
875
  onChange={onChange}
871
876
  isMulti={true}
877
+ context={context}
872
878
  />
873
879
  );
874
880
 
@@ -886,6 +892,186 @@ function FormField({ field, value, onChange }) {
886
892
 
887
893
  ---
888
894
 
895
+ ## 🔗 Field Context Passing
896
+
897
+ The React Core library supports **dynamic field dependencies** where form fields can access and respond to values from other fields in real-time. This enables complex form workflows where the options or behavior of one field depends on the selection made in another field.
898
+
899
+ ### **How Context Passing Works**
900
+
901
+ When a user selects a value in one field, that value becomes available to all other fields through the `context` parameter. This allows dependent fields to:
902
+
903
+ - Load different options based on the parent field's selection
904
+ - Show/hide fields based on other field values
905
+ - Update their behavior dynamically
906
+
907
+ ### **Implementation Example**
908
+
909
+ Here's how to implement context passing in your form components:
910
+
911
+ ```tsx
912
+ import { useConfigurationForm } from "@fastn-ai/react-core";
913
+
914
+ function ConfigurationForm({ configurationId, connectorId, configuration }) {
915
+ const { data: configurationForm, isLoading, error } = useConfigurationForm({
916
+ configurationId,
917
+ connectorId,
918
+ configuration,
919
+ });
920
+
921
+ return (
922
+ <Formik
923
+ initialValues={initialValues}
924
+ onSubmit={handleSubmit}
925
+ >
926
+ {({ values, setFieldValue, setFieldTouched, errors, touched }) => (
927
+ <Form>
928
+ {configurationForm.fields
929
+ .filter((field) => !field.hidden)
930
+ .map((field) => (
931
+ <FormField
932
+ key={field.name}
933
+ field={field}
934
+ form={{ values, errors, touched }}
935
+ setFieldValue={setFieldValue}
936
+ setFieldTouched={setFieldTouched}
937
+ context={values} // Pass all form values as context
938
+ />
939
+ ))}
940
+ </Form>
941
+ )}
942
+ </Formik>
943
+ );
944
+ }
945
+
946
+ // FormField component that passes context to individual fields
947
+ function FormField({ field, form, setFieldValue, setFieldTouched, context }) {
948
+ const handleChange = useCallback(
949
+ (value) => {
950
+ setFieldValue(field.name, value);
951
+ setFieldTouched(field.name, true);
952
+ },
953
+ [field.name, setFieldValue, setFieldTouched]
954
+ );
955
+
956
+ switch (field.type) {
957
+ case "select":
958
+ case "multi-select":
959
+ return (
960
+ <SelectField
961
+ field={field}
962
+ onChange={handleChange}
963
+ value={form.values[field.name]}
964
+ isMulti={field.type === "multi-select"}
965
+ context={context} // Pass context to SelectField
966
+ />
967
+ );
968
+ // ... other field types
969
+ }
970
+ }
971
+
972
+ // SelectField component that uses context
973
+ function SelectField({ field, onChange, value, isMulti, context }) {
974
+ // The useFieldOptions hook receives the context and can use it
975
+ // to fetch options based on other field values
976
+ const {
977
+ options,
978
+ loading,
979
+ loadingMore,
980
+ hasNext,
981
+ loadMore,
982
+ error,
983
+ search,
984
+ refresh,
985
+ totalLoadedOptions,
986
+ } = useFieldOptions(field, context);
987
+
988
+ const handleChange = useCallback(
989
+ (selected) => {
990
+ onChange(selected);
991
+ // When this field changes, the context is automatically updated
992
+ // and passed to all other fields
993
+ },
994
+ [onChange]
995
+ );
996
+
997
+ // ... rest of component implementation
998
+ }
999
+ ```
1000
+
1001
+ ### **Context Structure**
1002
+
1003
+ The `context` parameter contains all current form values in the following structure:
1004
+
1005
+ ```tsx
1006
+ // Example context object
1007
+ const context = {
1008
+ workspace: { label: "My Workspace", value: "ws_123" },
1009
+ channel: { label: "General", value: "ch_456" },
1010
+ webhookUrl: "https://hooks.slack.com/...",
1011
+ enableNotifications: true,
1012
+ // ... other field values
1013
+ };
1014
+ ```
1015
+
1016
+ ### **Use Cases**
1017
+
1018
+ 1. **Workspace → Channel Selection**: When a user selects a workspace, the channel field loads only channels from that workspace.
1019
+
1020
+ 2. **Database → Table Selection**: When a database is selected, the table field shows only tables from that database.
1021
+
1022
+ 3. **Conditional Field Display**: Show/hide fields based on other field values.
1023
+
1024
+ 4. **Dynamic Option Loading**: Load different options based on parent field selections.
1025
+
1026
+ ### **Best Practices**
1027
+
1028
+ 1. **Always pass context**: Make sure to pass the `context` parameter to all field components that need access to other field values.
1029
+
1030
+ 2. **Handle loading states**: When context changes, dependent fields may need to reload their options, so handle loading states appropriately.
1031
+
1032
+ 3. **Optimize re-renders**: Use `useCallback` and `useMemo` to prevent unnecessary re-renders when context changes.
1033
+
1034
+ 4. **Error handling**: Handle cases where context-dependent operations fail gracefully.
1035
+
1036
+ ### **Advanced Example: Multi-level Dependencies**
1037
+
1038
+ ```tsx
1039
+ // Example: Workspace → Channel → User selection
1040
+ function MultiLevelSelectForm() {
1041
+ const [formValues, setFormValues] = useState({});
1042
+
1043
+ return (
1044
+ <div>
1045
+ {/* Workspace selection */}
1046
+ <SelectField
1047
+ field={workspaceField}
1048
+ value={formValues.workspace}
1049
+ onChange={(value) => setFormValues(prev => ({ ...prev, workspace: value }))}
1050
+ context={formValues}
1051
+ />
1052
+
1053
+ {/* Channel selection - depends on workspace */}
1054
+ <SelectField
1055
+ field={channelField}
1056
+ value={formValues.channel}
1057
+ onChange={(value) => setFormValues(prev => ({ ...prev, channel: value }))}
1058
+ context={formValues} // Has access to workspace value
1059
+ />
1060
+
1061
+ {/* User selection - depends on both workspace and channel */}
1062
+ <SelectField
1063
+ field={userField}
1064
+ value={formValues.user}
1065
+ onChange={(value) => setFormValues(prev => ({ ...prev, user: value }))}
1066
+ context={formValues} // Has access to both workspace and channel values
1067
+ />
1068
+ </div>
1069
+ );
1070
+ }
1071
+ ```
1072
+
1073
+ ---
1074
+
889
1075
  ### **Error Handling and Loading States**
890
1076
 
891
1077
  ```tsx
@@ -1 +1 @@
1
- export declare const useConnectors: () => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").Connector[], Error>;
1
+ export declare const useConnectors: () => import("@tanstack/react-query").UseQueryResult<import("@fastn-ai/core").Connector[], Error>;
@@ -23,7 +23,7 @@ import type { ConnectorField, SelectOption, FormData } from "@fastn-ai/core";
23
23
  * // Pagination is managed with infinite query
24
24
  * ```
25
25
  */
26
- export declare function useFieldOptions(field: ConnectorField, context?: FormData): {
26
+ export declare function useFieldOptions(field: ConnectorField, context?: FormData | object): {
27
27
  options: SelectOption[];
28
28
  loading: boolean;
29
29
  loadingMore: boolean;
package/dist/index.d.ts CHANGED
@@ -41,7 +41,7 @@ declare const useConnectors: () => _tanstack_react_query.UseQueryResult<_fastn_a
41
41
  * // Pagination is managed with infinite query
42
42
  * ```
43
43
  */
44
- declare function useFieldOptions(field: ConnectorField, context?: FormData): {
44
+ declare function useFieldOptions(field: ConnectorField, context?: FormData | object): {
45
45
  options: SelectOption[];
46
46
  loading: boolean;
47
47
  loadingMore: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-fastn-ai/react-core",
3
- "version": "2.4.4",
3
+ "version": "2.4.6",
4
4
  "description": "React hooks and components for integrating Fastn AI connector marketplace into your applications. Built on top of @fastn-ai/core with React Query for optimal performance.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -52,15 +52,15 @@
52
52
  "license": "MIT",
53
53
  "repository": {
54
54
  "type": "git",
55
- "url": "https://github.com/fastn-ai/react-core.git"
55
+ "url": "https://github.com/dev-fastn-ai/react-core.git"
56
56
  },
57
57
  "bugs": {
58
- "url": "https://github.com/fastn-ai/react-core/issues"
58
+ "url": "https://github.com/dev-fastn-ai/react-core/issues"
59
59
  },
60
60
  "homepage": "https://docs.fastn.ai",
61
61
  "dependencies": {
62
62
  "@dev-fastn-ai/core": "^2.0.7",
63
- "@fastn-ai/core": "^1.0.4",
63
+ "@fastn-ai/core": "^1.0.5",
64
64
  "@types/lodash": "^4.17.20",
65
65
  "lodash": "^4.17.21"
66
66
  },
@@ -89,4 +89,4 @@
89
89
  "publishConfig": {
90
90
  "access": "public"
91
91
  }
92
- }
92
+ }