libmodulor 0.15.0 → 0.17.0

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 (65) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +3 -3
  4. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +1 -1
  5. package/dist/esm/index.react.d.ts +2 -1
  6. package/dist/esm/index.react.js +2 -1
  7. package/dist/esm/index.rn.d.ts +1 -0
  8. package/dist/esm/index.rn.js +1 -0
  9. package/dist/esm/std/ShellCommandExecutor.d.ts +1 -1
  10. package/dist/esm/target/lib/react/DIContextProvider.d.ts +1 -3
  11. package/dist/esm/target/lib/react/StyleContextProvider.d.ts +32 -0
  12. package/dist/esm/target/lib/react/StyleContextProvider.js +16 -0
  13. package/dist/esm/target/lib/react/UCEntrypoint.d.ts +1 -1
  14. package/dist/esm/target/lib/react/UCEntrypoint.js +2 -2
  15. package/dist/esm/target/lib/react/UCOutputFieldValueFragment.d.ts +4 -5
  16. package/dist/esm/target/lib/react/UCOutputFieldValueFragment.js +2 -2
  17. package/dist/esm/target/lib/react/UCPanel.js +9 -12
  18. package/dist/esm/target/lib/react/entrypoint.d.ts +1 -1
  19. package/dist/esm/target/lib/react/form.d.ts +10 -11
  20. package/dist/esm/target/lib/react/form.js +4 -0
  21. package/dist/esm/target/lib/react/touchable.d.ts +2 -3
  22. package/dist/esm/target/lib/react/useAction.d.ts +1 -1
  23. package/dist/esm/target/lib/react/useAction.js +11 -13
  24. package/dist/esm/target/lib/rn/input.d.ts +2 -2
  25. package/dist/esm/target/lib/rn/input.js +3 -3
  26. package/dist/esm/target/lib/web/input.d.ts +2 -3
  27. package/dist/esm/target/lib/web/input.js +3 -4
  28. package/dist/esm/target/react-native-pure/UCAutoExecLoader.js +3 -1
  29. package/dist/esm/target/react-native-pure/UCEntrypointTouchable.js +3 -1
  30. package/dist/esm/target/react-native-pure/UCExecTouchable.js +3 -1
  31. package/dist/esm/target/react-native-pure/UCForm.js +4 -3
  32. package/dist/esm/target/react-native-pure/UCFormField.js +4 -1
  33. package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +2 -2
  34. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +62 -5
  35. package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +3 -1
  36. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +3 -1
  37. package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +7 -1
  38. package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +4 -2
  39. package/dist/esm/target/react-native-pure/UCOutputFieldValue.js +3 -1
  40. package/dist/esm/target/react-web-pure/UCAutoExecLoader.js +3 -1
  41. package/dist/esm/target/react-web-pure/UCEntrypointTouchable.d.ts +1 -1
  42. package/dist/esm/target/react-web-pure/UCEntrypointTouchable.js +4 -2
  43. package/dist/esm/target/react-web-pure/UCExecTouchable.d.ts +1 -1
  44. package/dist/esm/target/react-web-pure/UCExecTouchable.js +4 -2
  45. package/dist/esm/target/react-web-pure/UCForm.d.ts +1 -1
  46. package/dist/esm/target/react-web-pure/UCForm.js +4 -2
  47. package/dist/esm/target/react-web-pure/UCFormField.d.ts +1 -1
  48. package/dist/esm/target/react-web-pure/UCFormField.js +4 -2
  49. package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +2 -2
  50. package/dist/esm/target/react-web-pure/UCFormFieldControl.js +26 -5
  51. package/dist/esm/target/react-web-pure/UCFormFieldDesc.d.ts +1 -1
  52. package/dist/esm/target/react-web-pure/UCFormFieldDesc.js +4 -2
  53. package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +1 -1
  54. package/dist/esm/target/react-web-pure/UCFormFieldErr.js +4 -2
  55. package/dist/esm/target/react-web-pure/UCFormFieldLabel.d.ts +1 -1
  56. package/dist/esm/target/react-web-pure/UCFormFieldLabel.js +8 -3
  57. package/dist/esm/target/react-web-pure/UCFormSubmitControl.d.ts +1 -1
  58. package/dist/esm/target/react-web-pure/UCFormSubmitControl.js +4 -2
  59. package/dist/esm/target/react-web-pure/UCOutputFieldValue.d.ts +1 -1
  60. package/dist/esm/target/react-web-pure/UCOutputFieldValue.js +5 -3
  61. package/dist/esm/uc/impl/RNUCClientConfirmManager.d.ts +10 -0
  62. package/dist/esm/uc/impl/RNUCClientConfirmManager.js +44 -0
  63. package/dist/esm/utils/ioc/bindRN.js +5 -0
  64. package/package.json +4 -4
  65. package/pnpm-workspace.yaml +9 -0
package/CHANGELOG.md CHANGED
@@ -1,7 +1,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.17.0 (2025-06-02)
4
+
5
+ **BREAKING**
6
+
7
+ - Make `target/react-native-pure` and `target/react-web-pure` components stylable : by using the new `<StyleContextProvider style={...style} />` you can customize how the elements render inside `<UCPanel />`. You can even use `renderFormFieldControl` to customize the form controls rendered according to the field (e.g. name, type, etc.)
8
+
9
+ ## v0.16.0 (2025-05-27)
10
+
11
+ **BREAKING**
12
+
13
+ - Make `pnpm` (in replacement of `yarn`) the default package manager in `npx libmodulor CreateProject`
14
+
3
15
  ## v0.15.0 (2025-05-25)
4
16
 
17
+ **Added**
18
+
5
19
  - In `LLMManager`, allow to pass the `apiKey` directly in the request. It precedes the settings value defined at the implementation level
6
20
  - In `target/react`, add optional `className` to stylable components
7
21
  - In `target/web`, handle use case input field initial value
package/README.md CHANGED
@@ -17,4 +17,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
17
17
 
18
18
  ## ⚖️ License
19
19
 
20
- [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.15.0/LICENSE)
20
+ [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.17.0/LICENSE)
@@ -42,8 +42,8 @@ export const PACKAGE_JSON = (name) => `{
42
42
  },
43
43
  "devDependencies": {
44
44
  "@biomejs/biome": "^1.9.4",
45
- "@types/node": "^22.15.19",
46
- "@vitest/coverage-v8": "^3.1.3",
45
+ "@types/node": "^22.15.21",
46
+ "@vitest/coverage-v8": "^3.1.4",
47
47
  "buffer": "^6.0.3",
48
48
  "cookie-parser": "^1.4.7",
49
49
  "express": "^5.1.0",
@@ -53,7 +53,7 @@ export const PACKAGE_JSON = (name) => `{
53
53
  "jose": "^6.0.11",
54
54
  "typescript": "^5.8.3",
55
55
  "vite": "^6.3.5",
56
- "vitest": "^3.1.3"
56
+ "vitest": "^3.1.4"
57
57
  }
58
58
  }
59
59
  `;
@@ -156,7 +156,7 @@ export const CreateProjectUCD = {
156
156
  min: 0,
157
157
  },
158
158
  type: new TFileName()
159
- .setDefaultValue('yarn')
159
+ .setDefaultValue('pnpm')
160
160
  .setExamples(['bun', 'npm', 'pnpm', 'yarn']),
161
161
  },
162
162
  projectName: {
@@ -1,4 +1,5 @@
1
- export { DIContext, useDIContext, DIContextProvider, type DIContextT, } from './target/lib/react/DIContextProvider.js';
1
+ export { DIContext, DIContextProvider, type DIContextT, useDIContext, } from './target/lib/react/DIContextProvider.js';
2
+ export { StyleContext, StyleContextProvider, type StyleContextT, styleDef, useStyleContext, } from './target/lib/react/StyleContextProvider.js';
2
3
  export type { UCFormFieldControlOnChange, UCFormFieldControlProps, UCFormFieldDescProps, UCFormFieldElement, UCFormFieldErrProps, UCFormFieldLabelProps, UCFormFieldProps, UCFormProps, UCFormSubmitControlProps, UC_FORM_FIELD_ELEMENTS, RenderUCForm, validateFormField, } from './target/lib/react/form.js';
3
4
  export type { UCPanelCtx, UCPanelOnDone, UCPanelOnError, UCPanelOnInit, UCPanelOnStartSubmitting, UCPanelOnSubmit, UCPanelState, } from './target/lib/react/panel.js';
4
5
  export type { UCEntrypointTouchableProps, RenderUCEntrypointTouchable, RenderUCExecTouchable, UCExecTouchableProps, } from './target/lib/react/touchable.js';
@@ -1,4 +1,5 @@
1
- export { DIContext, useDIContext, DIContextProvider, } from './target/lib/react/DIContextProvider.js';
1
+ export { DIContext, DIContextProvider, useDIContext, } from './target/lib/react/DIContextProvider.js';
2
+ export { StyleContext, StyleContextProvider, styleDef, useStyleContext, } from './target/lib/react/StyleContextProvider.js';
2
3
  export { UCContainer } from './target/lib/react/UCContainer.js';
3
4
  export { UCEntrypoint } from './target/lib/react/UCEntrypoint.js';
4
5
  export { UCOutputFieldValueFragment, } from './target/lib/react/UCOutputFieldValueFragment.js';
@@ -1,2 +1,3 @@
1
1
  export { BufferLibBufferManager } from './std/impl/BufferLibBufferManager.js';
2
+ export { RNUCClientConfirmManager } from './uc/impl/RNUCClientConfirmManager.js';
2
3
  export { bindRN } from './utils/ioc/bindRN.js';
@@ -1,2 +1,3 @@
1
1
  export { BufferLibBufferManager } from './std/impl/BufferLibBufferManager.js';
2
+ export { RNUCClientConfirmManager } from './uc/impl/RNUCClientConfirmManager.js';
2
3
  export { bindRN } from './utils/ioc/bindRN.js';
@@ -1,7 +1,7 @@
1
1
  import type { FilePath } from '../dt/index.js';
2
2
  import type { Worker } from './Worker.js';
3
3
  export type ShellCommandExecutorCommandArg = string;
4
- export type ShellCommandExecutorCommandBin = 'docker' | 'file' | 'git' | 'open' | 'ssh-keygen' | 'ssh-keyscan' | 'unzip' | 'yarn' | 'zip' | (string & {});
4
+ export type ShellCommandExecutorCommandBin = 'bun' | 'docker' | 'file' | 'git' | 'npm' | 'open' | 'pnpm' | 'ssh-keygen' | 'ssh-keyscan' | 'unzip' | 'yarn' | 'zip' | (string & {});
5
5
  export type ShellCommandExecutorEnv = Record<string, string>;
6
6
  export type ShellCommandExecutorInstruction = string;
7
7
  export type ShellCommandExecutorScript = string;
@@ -9,8 +9,6 @@ export interface DIContextT {
9
9
  }
10
10
  export declare const DIContext: React.Context<DIContextT | null>;
11
11
  export declare function useDIContext(): DIContextT;
12
- interface Props {
13
- container: Container;
14
- }
12
+ type Props = Pick<DIContextT, 'container'>;
15
13
  export declare function DIContextProvider({ children, container, }: PropsWithChildren<Props>): ReactElement;
16
14
  export {};
@@ -0,0 +1,32 @@
1
+ import React, { type PropsWithChildren, type ReactElement } from 'react';
2
+ import type { Color, DataType } from '../../../dt/index.js';
3
+ import type { UCFormFieldControlProps } from './form.js';
4
+ export interface StyleDef {
5
+ className?: string | undefined;
6
+ style?: Record<string, unknown> | undefined;
7
+ }
8
+ export type SelectiveStyleDefKey = 'default' | (string & {});
9
+ export interface StyleContextT {
10
+ autoExecLoader?: StyleDef | undefined;
11
+ colors?: {
12
+ onPrimary: Color;
13
+ primary: Color;
14
+ };
15
+ entrypointTouchable?: StyleDef | undefined;
16
+ execTouchable?: StyleDef | undefined;
17
+ form?: StyleDef | undefined;
18
+ formField?: StyleDef | undefined;
19
+ formFieldControl?: Record<SelectiveStyleDefKey, StyleDef | undefined>;
20
+ formFieldDesc?: StyleDef | undefined;
21
+ formFieldErr?: StyleDef | undefined;
22
+ formFieldLabel?: StyleDef | undefined;
23
+ formSubmitControl?: StyleDef | undefined;
24
+ outputFieldValue?: StyleDef | undefined;
25
+ renderFormFieldControl?: <T extends DataType>(props: UCFormFieldControlProps<T>) => ReactElement | null;
26
+ }
27
+ export declare const StyleContext: React.Context<StyleContextT>;
28
+ export declare function useStyleContext(): StyleContextT;
29
+ type Props = StyleContextT;
30
+ export declare function StyleContextProvider({ children, ...rest }: PropsWithChildren<Props>): ReactElement;
31
+ export declare function styleDef(def: StyleContextT['formFieldControl'], k1: SelectiveStyleDefKey, fallback?: SelectiveStyleDefKey | undefined): StyleDef;
32
+ export {};
@@ -0,0 +1,16 @@
1
+ import React, { createContext, useContext, } from 'react';
2
+ export const StyleContext = createContext({});
3
+ export function useStyleContext() {
4
+ return useContext(StyleContext);
5
+ }
6
+ export function StyleContextProvider({ children, ...rest }) {
7
+ return (React.createElement(StyleContext.Provider, { value: rest }, children));
8
+ }
9
+ export function styleDef(def, k1, fallback) {
10
+ const main = def?.[k1];
11
+ const fb = fallback ? def?.[fallback] : null;
12
+ return {
13
+ className: main?.className ?? fb?.className,
14
+ style: main?.style ?? fb?.style,
15
+ };
16
+ }
@@ -5,5 +5,5 @@ import type { RenderUCEntrypointTouchable } from './touchable.js';
5
5
  type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCEntrypointCtx<I, OPI0, OPI1> & {
6
6
  renderTouchable: RenderUCEntrypointTouchable<I, OPI0, OPI1>;
7
7
  };
8
- export declare function UCEntrypoint<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ path, renderTouchable, uc }: Props<I, OPI0, OPI1>): ReactElement;
8
+ export declare function UCEntrypoint<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ onPress, path, renderTouchable, uc }: Props<I, OPI0, OPI1>): ReactElement;
9
9
  export {};
@@ -1,8 +1,8 @@
1
1
  import React, {} from 'react';
2
2
  import { useDIContext } from './DIContextProvider.js';
3
3
  import { UCContainer } from './UCContainer.js';
4
- export function UCEntrypoint({ path, renderTouchable, uc }) {
4
+ export function UCEntrypoint({ onPress, path, renderTouchable, uc }) {
5
5
  const { wordingManager } = useDIContext();
6
6
  const wording = wordingManager.uc(uc.def);
7
- return (React.createElement(UCContainer, { uc: uc }, renderTouchable({ path, uc, wording })));
7
+ return (React.createElement(UCContainer, { uc: uc }, renderTouchable({ onPress, path, uc, wording })));
8
8
  }
@@ -1,9 +1,8 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { DataType } from '../../../dt/index.js';
3
3
  import type { UCOPIBase, UCOutputField } from '../../../uc/index.js';
4
- import type { Stylable } from './common.js';
5
- export type Props<OPI extends UCOPIBase, T extends DataType> = Stylable & {
6
- field: UCOutputField<OPI, T>;
4
+ export interface Props<OPI extends UCOPIBase, T extends DataType> {
5
+ f: UCOutputField<OPI, T>;
7
6
  value: T;
8
- };
9
- export declare function UCOutputFieldValueFragment<OPI extends UCOPIBase, T extends DataType>({ field, value }: Props<OPI, T>): ReactElement;
7
+ }
8
+ export declare function UCOutputFieldValueFragment<OPI extends UCOPIBase, T extends DataType>({ f, value }: Props<OPI, T>): ReactElement;
@@ -1,6 +1,6 @@
1
1
  import React, {} from 'react';
2
- export function UCOutputFieldValueFragment({ field, value }) {
3
- const { def: { type }, } = field;
2
+ export function UCOutputFieldValueFragment({ f, value }) {
3
+ const { def: { type }, } = f;
4
4
  type.assign(value);
5
5
  return React.createElement(React.Fragment, null, type.fmt());
6
6
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { ucIsDisabled, ucIsLoading, } from '../../../uc/index.js';
2
+ import { ucIsDisabled, } from '../../../uc/index.js';
3
3
  import { sleep } from '../../../utils/index.js';
4
4
  import { useDIContext } from './DIContextProvider.js';
5
5
  import { UCContainer } from './UCContainer.js';
@@ -35,28 +35,25 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
35
35
  }
36
36
  uc.clear();
37
37
  };
38
- const disabled = ucIsDisabled(execState);
39
- const loading = ucIsLoading(execState);
40
- // TODO : Keep these as a state to avoid recomputation
38
+ const needsInputFilling = uc.needsInputFilling();
41
39
  const ctx = {
42
40
  clearAfterExec,
43
- disabled,
41
+ disabled: ucIsDisabled(execState),
44
42
  execState,
45
43
  uc,
46
44
  };
47
- const needsInputFilling = uc.needsInputFilling();
48
45
  return (React.createElement(UCContainer, { uc: uc },
49
- autoExec && loading && renderAutoExecLoader(),
46
+ autoExec && ctx.disabled && renderAutoExecLoader(),
50
47
  !autoExec && (React.createElement(React.Fragment, null,
51
- !needsInputFilling &&
52
- renderExecTouchable({
53
- ...ctx,
54
- onSubmit: exec,
55
- }),
56
48
  needsInputFilling &&
57
49
  renderForm({
58
50
  ...ctx,
59
51
  onChange,
60
52
  onSubmit: exec,
53
+ }),
54
+ !needsInputFilling &&
55
+ renderExecTouchable({
56
+ ...ctx,
57
+ onSubmit: exec,
61
58
  })))));
62
59
  }
@@ -2,7 +2,7 @@ import type { URLPath } from '../../../dt/index.js';
2
2
  import type { UC, UCInput, UCOPIBase } from '../../../uc/index.js';
3
3
  export type UCEntrypointOnPress = () => Promise<void>;
4
4
  export interface UCEntrypointCtx<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> {
5
- onPress?: UCEntrypointOnPress;
5
+ onPress?: UCEntrypointOnPress | undefined;
6
6
  path?: URLPath | undefined;
7
7
  uc: UC<I, OPI0, OPI1>;
8
8
  }
@@ -2,33 +2,32 @@ import type { ReactElement } from 'react';
2
2
  import type { DataType, ErrorMessage } from '../../../dt/index.js';
3
3
  import type { I18nManager } from '../../../std/index.js';
4
4
  import type { UCInput, UCInputField, UCInputFieldChangeOperator, UCInputFieldValue, UCOPIBase } from '../../../uc/index.js';
5
- import type { Stylable } from './common.js';
6
5
  import type { UCPanelCtx, UCPanelOnSubmit, UCPanelState } from './panel.js';
7
6
  export type UCFormFieldControlOnChange<T extends DataType = DataType> = (f: UCInputField<T>, op: UCInputFieldChangeOperator, v: UCInputFieldValue<T>) => void;
8
- export type UCFormFieldControlProps<T extends DataType> = Stylable & UCPanelState & {
7
+ export type UCFormFieldControlProps<T extends DataType> = UCPanelState & {
9
8
  errMsg?: ErrorMessage | null;
10
9
  f: UCInputField<T>;
11
10
  onChange: UCFormFieldControlOnChange<T>;
12
11
  };
13
- export type UCFormFieldDescProps<T extends DataType> = Stylable & {
12
+ export interface UCFormFieldDescProps<T extends DataType> {
14
13
  f: UCInputField<T>;
15
- };
16
- export type UCFormFieldErrProps = Stylable & {
14
+ }
15
+ export interface UCFormFieldErrProps {
17
16
  errMsg?: ErrorMessage | null;
18
- };
19
- export type UCFormFieldLabelProps<T extends DataType> = Stylable & {
17
+ }
18
+ export interface UCFormFieldLabelProps<T extends DataType> {
20
19
  f: UCInputField<T>;
21
- };
20
+ }
22
21
  export declare const UC_FORM_FIELD_ELEMENTS: readonly ["control", "desc", "err", "label"];
23
22
  export type UCFormFieldElement = (typeof UC_FORM_FIELD_ELEMENTS)[number];
24
- export type UCFormFieldProps<T extends DataType> = Stylable & UCFormFieldControlProps<T> & {
23
+ export type UCFormFieldProps<T extends DataType> = UCFormFieldControlProps<T> & {
25
24
  only?: UCFormFieldElement[];
26
25
  };
27
- export type UCFormProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Stylable & UCPanelCtx<I, OPI0, OPI1> & {
26
+ export type UCFormProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
28
27
  onChange: UCFormFieldControlOnChange;
29
28
  onSubmit: UCPanelOnSubmit;
30
29
  };
31
- export type UCFormSubmitControlProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Stylable & UCPanelCtx<I, OPI0, OPI1> & {
30
+ export type UCFormSubmitControlProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
32
31
  onPress?: () => Promise<void>;
33
32
  };
34
33
  export type RenderUCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (props: UCFormProps<I, OPI0, OPI1>) => ReactElement;
@@ -1,3 +1,4 @@
1
+ import { isBlank } from '../../../utils/index.js';
1
2
  export const UC_FORM_FIELD_ELEMENTS = [
2
3
  'control',
3
4
  'desc',
@@ -5,6 +6,9 @@ export const UC_FORM_FIELD_ELEMENTS = [
5
6
  'label',
6
7
  ];
7
8
  export function validateFormField(i18nManager, f, v) {
9
+ if (isBlank(v)) {
10
+ return null;
11
+ }
8
12
  const vArr = Array.isArray(v) ? v : [v];
9
13
  for (const vv of vArr) {
10
14
  const validation = f.def.type.assign(vv).validate();
@@ -1,13 +1,12 @@
1
1
  import type { ReactElement } from 'react';
2
2
  import type { UCInput, UCOPIBase, UCWording } from '../../../uc/index.js';
3
- import type { Stylable } from './common.js';
4
3
  import type { UCEntrypointCtx } from './entrypoint.js';
5
4
  import type { UCPanelCtx, UCPanelOnSubmit } from './panel.js';
6
- export type UCEntrypointTouchableProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Stylable & UCEntrypointCtx<I, OPI0, OPI1> & {
5
+ export type UCEntrypointTouchableProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCEntrypointCtx<I, OPI0, OPI1> & {
7
6
  wording: UCWording;
8
7
  };
9
8
  export type RenderUCEntrypointTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (props: UCEntrypointTouchableProps<I, OPI0, OPI1>) => ReactElement;
10
- export type UCExecTouchableProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Stylable & UCPanelCtx<I, OPI0, OPI1> & {
9
+ export type UCExecTouchableProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
11
10
  onSubmit: UCPanelOnSubmit;
12
11
  };
13
12
  export type RenderUCExecTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (props: UCExecTouchableProps<I, OPI0, OPI1>) => ReactElement;
@@ -1,5 +1,5 @@
1
1
  import type { ErrorMessage, UIntDuration } from '../../../dt/index.js';
2
- import type { UCExecRes, UCExecState } from '../../../uc/exec.js';
2
+ import type { UCExecRes, UCExecState } from '../../../uc/index.js';
3
3
  export type UseActionAction = () => Promise<void>;
4
4
  export type UseActionConfirm = () => Promise<boolean>;
5
5
  export type UseActionExec = () => Promise<UCExecRes>;
@@ -4,15 +4,20 @@ export function useAction({ action, autoExec = false, confirm, onError, onInit,
4
4
  const [errMsg, setErrMsg] = useState(null);
5
5
  const [execRes, setExecRes] = useState(null);
6
6
  const [execState, setExecState] = useState(onInit ? 'initializing' : 'idle');
7
+ // biome-ignore lint/correctness/useExhaustiveDependencies : must run only once
7
8
  useEffect(() => {
8
- if (execState !== 'initializing') {
9
- return;
10
- }
11
9
  (async () => {
12
- await onInit?.();
13
- setExecState('idle');
10
+ if (execState === 'initializing') {
11
+ await onInit?.();
12
+ }
13
+ if (autoExec) {
14
+ await exec();
15
+ }
16
+ else {
17
+ setExecState('idle');
18
+ }
14
19
  })();
15
- }, [execState, onInit]);
20
+ }, []);
16
21
  const exec = async () => {
17
22
  setErrMsg(null);
18
23
  setExecRes(null);
@@ -46,12 +51,5 @@ export function useAction({ action, autoExec = false, confirm, onError, onInit,
46
51
  setExecState('idle');
47
52
  }
48
53
  };
49
- // biome-ignore lint/correctness/useExhaustiveDependencies(exec): it complains if I add it AND if I don't add it !
50
- useEffect(() => {
51
- if (!autoExec) {
52
- return;
53
- }
54
- exec();
55
- }, [autoExec]);
56
54
  return { errMsg, exec, execRes, execState };
57
55
  }
@@ -1,6 +1,6 @@
1
1
  import type { TextInputProps } from 'react-native';
2
2
  import { type DataType, type ErrorMessage } from '../../../dt/index.js';
3
- import { type UCExecState, type UCInputField } from '../../../uc/index.js';
3
+ import { type UCInputField } from '../../../uc/index.js';
4
4
  export interface RNInputDef {
5
5
  internal?: undefined;
6
6
  /**
@@ -12,4 +12,4 @@ export interface RNInputDef {
12
12
  */
13
13
  spec?: TextInputProps;
14
14
  }
15
- export declare function rnInputDef<T extends DataType>(field: UCInputField<T>, execState: UCExecState, _errMsg: ErrorMessage | null): RNInputDef;
15
+ export declare function rnInputDef<T extends DataType>(field: UCInputField<T>, disabled: boolean, _errMsg: ErrorMessage | null): RNInputDef;
@@ -1,6 +1,6 @@
1
1
  import { TString, } from '../../../dt/index.js';
2
- import { ucIsDisabled, ucifHint, ucifId, } from '../../../uc/index.js';
3
- export function rnInputDef(field, execState, _errMsg) {
2
+ import { ucifHint, ucifId } from '../../../uc/index.js';
3
+ export function rnInputDef(field, disabled, _errMsg) {
4
4
  const def = {
5
5
  internal: undefined,
6
6
  spec: {},
@@ -11,7 +11,7 @@ export function rnInputDef(field, execState, _errMsg) {
11
11
  }
12
12
  const { key, def: fDef } = field;
13
13
  const { type: fType } = fDef;
14
- def.spec.editable = !ucIsDisabled(execState);
14
+ def.spec.editable = !disabled;
15
15
  def.spec.id = ucifId(key);
16
16
  // Testing the types by usage probability to make the if/else evaluation stop ideally earlier
17
17
  if (fType instanceof TString) {
@@ -1,5 +1,5 @@
1
1
  import { type DataType, type ErrorMessage, type HTMLInputType } from '../../../dt/index.js';
2
- import { type UCExecState, type UCInputField } from '../../../uc/index.js';
2
+ import { type UCInputField } from '../../../uc/index.js';
3
3
  export interface HTMLInputDef {
4
4
  /**
5
5
  * Internal types that are not part of the W3C spec
@@ -36,7 +36,6 @@ export interface HTMLInputDef {
36
36
  spec?: {
37
37
  'aria-errormessage'?: string | undefined;
38
38
  'aria-invalid'?: boolean | undefined;
39
- className?: string | undefined;
40
39
  disabled?: boolean | undefined;
41
40
  id?: string | undefined;
42
41
  max?: number | undefined;
@@ -51,4 +50,4 @@ export interface HTMLInputDef {
51
50
  type?: HTMLInputType | undefined;
52
51
  };
53
52
  }
54
- export declare function htmlInputDef<T extends DataType>(field: UCInputField<T>, execState: UCExecState, errMsg: ErrorMessage | null, className: string | undefined): HTMLInputDef;
53
+ export declare function htmlInputDef<T extends DataType>(field: UCInputField<T>, disabled: boolean, errMsg: ErrorMessage | null): HTMLInputDef;
@@ -1,6 +1,6 @@
1
1
  import { TBoolean, TNumber, TString, } from '../../../dt/index.js';
2
- import { ucIsDisabled, ucifHint, ucifId, ucifIsMandatory, } from '../../../uc/index.js';
3
- export function htmlInputDef(field, execState, errMsg, className) {
2
+ import { ucifHint, ucifId, ucifIsMandatory, } from '../../../uc/index.js';
3
+ export function htmlInputDef(field, disabled, errMsg) {
4
4
  const def = {
5
5
  internal: {},
6
6
  spec: {},
@@ -11,8 +11,7 @@ export function htmlInputDef(field, execState, errMsg, className) {
11
11
  }
12
12
  const { key, def: fDef } = field;
13
13
  const { type: fType } = fDef;
14
- def.spec.className = className;
15
- def.spec.disabled = ucIsDisabled(execState);
14
+ def.spec.disabled = disabled;
16
15
  def.spec.id = ucifId(key);
17
16
  def.spec.name = key;
18
17
  // Testing the types by usage probability to make the if/else evaluation stop ideally earlier
@@ -1,5 +1,7 @@
1
1
  import React, {} from 'react';
2
2
  import { ActivityIndicator } from 'react-native';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  export function UCAutoExecLoader() {
4
- return React.createElement(ActivityIndicator, null);
5
+ const { autoExecLoader } = useStyleContext();
6
+ return React.createElement(ActivityIndicator, { style: autoExecLoader?.style });
5
7
  }
@@ -1,6 +1,8 @@
1
1
  import React, {} from 'react';
2
2
  import { Pressable, Text } from 'react-native';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  export function UCEntrypointTouchable({ onPress, wording, }) {
5
+ const { entrypointTouchable } = useStyleContext();
4
6
  return (React.createElement(Pressable, { onPress: onPress },
5
- React.createElement(Text, null, wording.label)));
7
+ React.createElement(Text, { style: entrypointTouchable?.style }, wording.label)));
6
8
  }
@@ -1,9 +1,11 @@
1
1
  import React, {} from 'react';
2
2
  import { Pressable, Text } from 'react-native';
3
3
  import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
5
  export function UCExecTouchable({ disabled, execState, onSubmit, uc, }) {
5
6
  const { wordingManager } = useDIContext();
7
+ const { execTouchable } = useStyleContext();
6
8
  const label = wordingManager.ucISubmit(uc.def, execState);
7
9
  return (React.createElement(Pressable, { disabled: disabled, onPress: onSubmit },
8
- React.createElement(Text, null, label)));
10
+ React.createElement(Text, { style: execTouchable?.style }, label)));
9
11
  }
@@ -1,13 +1,14 @@
1
1
  import React, {} from 'react';
2
2
  import { View } from 'react-native';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  import { UCFormField } from './UCFormField.js';
4
5
  import { UCFormSubmitControl } from './UCFormSubmitControl.js';
5
6
  export function UCForm({ disabled, execState, onChange, onSubmit, uc, }) {
7
+ const { form } = useStyleContext();
6
8
  const onPress = async () => {
7
9
  await onSubmit();
8
10
  };
9
- return (React.createElement(View, null,
10
- uc.inputFieldsForForm().map((f) => (React.createElement(View, { key: f.key },
11
- React.createElement(UCFormField, { disabled: disabled, execState: execState, f: f, onChange: onChange })))),
11
+ return (React.createElement(View, { style: form?.style },
12
+ uc.inputFieldsForForm().map((f) => (React.createElement(UCFormField, { disabled: disabled, execState: execState, f: f, key: f.key, onChange: onChange }))),
12
13
  React.createElement(UCFormSubmitControl, { execState: execState, disabled: disabled, onPress: onPress, uc: uc })));
13
14
  }
@@ -1,5 +1,7 @@
1
1
  import React, { useState } from 'react';
2
+ import { View } from 'react-native';
2
3
  import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
5
  import { UC_FORM_FIELD_ELEMENTS, validateFormField, } from '../lib/react/form.js';
4
6
  import { UCFormFieldControl } from './UCFormFieldControl.js';
5
7
  import { UCFormFieldDesc } from './UCFormFieldDesc.js';
@@ -7,13 +9,14 @@ import { UCFormFieldErr } from './UCFormFieldErr.js';
7
9
  import { UCFormFieldLabel } from './UCFormFieldLabel.js';
8
10
  export function UCFormField({ disabled, execState, f, onChange: onChangeBase, only, }) {
9
11
  const { i18nManager } = useDIContext();
12
+ const { formField } = useStyleContext();
10
13
  const [errMsg, setErrMsg] = useState(null);
11
14
  const onChange = (f, op, v) => {
12
15
  setErrMsg(validateFormField(i18nManager, f, v));
13
16
  onChangeBase(f, op, v);
14
17
  };
15
18
  const elements = only ?? UC_FORM_FIELD_ELEMENTS;
16
- return (React.createElement(React.Fragment, null,
19
+ return (React.createElement(View, { style: formField?.style },
17
20
  elements.includes('label') && React.createElement(UCFormFieldLabel, { f: f }),
18
21
  elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })),
19
22
  elements.includes('err') && errMsg && (React.createElement(UCFormFieldErr, { errMsg: errMsg })),
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
- import type { DataType } from '../../dt/index.js';
2
+ import { type DataType } from '../../dt/index.js';
3
3
  import type { UCFormFieldControlProps } from '../lib/react/form.js';
4
- export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
4
+ export declare function UCFormFieldControl<T extends DataType>({ disabled, errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
@@ -1,16 +1,29 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { TextInput } from 'react-native';
2
+ import { FlatList, Pressable, StyleSheet, Switch, Text, TextInput, } from 'react-native';
3
+ import { TBoolean } from '../../dt/index.js';
3
4
  import { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.js';
4
5
  import { isBlank } from '../../utils/index.js';
6
+ import { styleDef, useStyleContext, } from '../lib/react/StyleContextProvider.js';
5
7
  import { rnInputDef } from '../lib/rn/input.js';
6
8
  const MULTIPLE_VALUES_SEPARATOR = ',';
7
- export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onChangeBase, }) {
9
+ // TODO : Split this into smaller components
10
+ export function UCFormFieldControl({ disabled, errMsg = null, execState, f, onChange: onChangeBase, }) {
11
+ const { colors, formFieldControl, renderFormFieldControl } = useStyleContext();
12
+ const component = renderFormFieldControl?.({
13
+ disabled,
14
+ errMsg,
15
+ execState,
16
+ f,
17
+ onChange: onChangeBase,
18
+ });
19
+ if (component) {
20
+ return component;
21
+ }
8
22
  const [internalValue, setInternalValue] = useState(f.getValue());
9
- // biome-ignore lint/correctness/useExhaustiveDependencies: false positive : It is actually necessary (only `field` does not trigger the effect)
23
+ // biome-ignore lint/correctness/useExhaustiveDependencies: false positive : It is actually necessary (only `f` does not trigger the effect)
10
24
  useEffect(() => {
11
25
  setInternalValue(f.getValue());
12
26
  }, [f.getValue()]);
13
- const attrs = rnInputDef(f, execState, errMsg);
14
27
  const onChangeText = (value) => {
15
28
  const [isRepeatable] = ucifRepeatability(f.def);
16
29
  if (isRepeatable && typeof value === 'string') {
@@ -24,6 +37,40 @@ export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onCh
24
37
  }
25
38
  setInternalValue(value);
26
39
  };
40
+ const onSelect = (value) => {
41
+ if (internalValue === value) {
42
+ onChangeBase(f, UCInputFieldChangeOperator.RESET, null);
43
+ setInternalValue(null);
44
+ return;
45
+ }
46
+ onChangeBase(f, UCInputFieldChangeOperator.SET, value);
47
+ setInternalValue(value);
48
+ };
49
+ const onValueChange = (value) => {
50
+ onChangeBase(f, UCInputFieldChangeOperator.SET, value);
51
+ setInternalValue(value);
52
+ };
53
+ const attrs = rnInputDef(f, disabled, errMsg);
54
+ const { type } = f.def;
55
+ const options = type.getOptions();
56
+ if (options) {
57
+ // TODO : Handle type.hasStrictOptions() => display an input text alongside the options
58
+ // TODO : Consider using a picker when the options count > X
59
+ return (React.createElement(FlatList, { data: options, horizontal: true, keyExtractor: (item) => item.value.toString(), renderItem: ({ item }) => (React.createElement(Pressable, { disabled: !attrs.spec?.editable, onPress: () => onSelect(item.value), style: [
60
+ styles.selectOption,
61
+ {
62
+ borderColor: item.value === internalValue
63
+ ? colors?.primary
64
+ : 'transparent',
65
+ },
66
+ ] },
67
+ React.createElement(Text, null, item.label))), showsHorizontalScrollIndicator: false, style: styles.select }));
68
+ }
69
+ // TODO : Implement picker for TFile (requires a dependency...)
70
+ if (type instanceof TBoolean) {
71
+ const { style } = styleDef(formFieldControl, 'Switch');
72
+ return (React.createElement(Switch, { disabled: !attrs.spec?.editable, trackColor: { true: colors?.primary }, onValueChange: onValueChange, style: style, value: internalValue }));
73
+ }
27
74
  let valueAsString = '';
28
75
  if (!isBlank(internalValue)) {
29
76
  if (Array.isArray(internalValue)) {
@@ -33,5 +80,15 @@ export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onCh
33
80
  valueAsString = internalValue.toString();
34
81
  }
35
82
  }
36
- return (React.createElement(TextInput, { ...attrs.spec, onChangeText: onChangeText, value: valueAsString }));
83
+ const { style } = styleDef(formFieldControl, 'TextInput', 'default');
84
+ return (React.createElement(TextInput, { ...attrs.spec, onChangeText: onChangeText, style: style, value: valueAsString }));
37
85
  }
86
+ const styles = StyleSheet.create({
87
+ select: {
88
+ flexGrow: 0, // Prevent the list from extending full height
89
+ },
90
+ selectOption: {
91
+ padding: 2,
92
+ borderWidth: 1,
93
+ },
94
+ });
@@ -1,11 +1,13 @@
1
1
  import React, {} from 'react';
2
2
  import { Text } from 'react-native';
3
3
  import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
5
  export function UCFormFieldDesc({ f, }) {
5
6
  const { wordingManager } = useDIContext();
7
+ const { formFieldDesc } = useStyleContext();
6
8
  const { desc } = wordingManager.ucif(f);
7
9
  if (!desc) {
8
10
  return null;
9
11
  }
10
- return React.createElement(Text, null, desc);
12
+ return React.createElement(Text, { style: formFieldDesc?.style }, desc);
11
13
  }
@@ -1,5 +1,7 @@
1
1
  import React, {} from 'react';
2
2
  import { Text } from 'react-native';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  export function UCFormFieldErr({ errMsg }) {
4
- return React.createElement(Text, null, errMsg);
5
+ const { formFieldErr } = useStyleContext();
6
+ return React.createElement(Text, { style: formFieldErr?.style }, errMsg);
5
7
  }
@@ -1,8 +1,14 @@
1
1
  import React, {} from 'react';
2
2
  import { Text } from 'react-native';
3
+ import { ucifIsMandatory } from '../../uc/index.js';
3
4
  import { useDIContext } from '../lib/react/DIContextProvider.js';
5
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
6
  export function UCFormFieldLabel({ f, }) {
5
7
  const { wordingManager } = useDIContext();
8
+ const { formFieldLabel } = useStyleContext();
6
9
  const { label } = wordingManager.ucif(f);
7
- return React.createElement(Text, null, label);
10
+ const mandatory = ucifIsMandatory(f.def);
11
+ return (React.createElement(Text, { style: formFieldLabel?.style },
12
+ label,
13
+ mandatory && ' *'));
8
14
  }
@@ -1,8 +1,10 @@
1
1
  import React, {} from 'react';
2
2
  import { Pressable, Text } from 'react-native';
3
3
  import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
5
  export function UCFormSubmitControl({ execState, disabled, onPress, uc, }) {
5
6
  const { wordingManager } = useDIContext();
6
- return (React.createElement(Pressable, { onPress: onPress, disabled: disabled },
7
- React.createElement(Text, null, wordingManager.ucISubmit(uc.def, execState))));
7
+ const { formSubmitControl } = useStyleContext();
8
+ return (React.createElement(Pressable, { disabled: disabled, onPress: onPress },
9
+ React.createElement(Text, { style: formSubmitControl?.style }, wordingManager.ucISubmit(uc.def, execState))));
8
10
  }
@@ -1,7 +1,9 @@
1
1
  import React, {} from 'react';
2
2
  import { Text } from 'react-native';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  import { UCOutputFieldValueFragment, } from '../lib/react/UCOutputFieldValueFragment.js';
4
5
  export function UCOutputFieldValue(props) {
5
- return (React.createElement(Text, null,
6
+ const { outputFieldValue } = useStyleContext();
7
+ return (React.createElement(Text, { style: outputFieldValue?.style },
6
8
  React.createElement(UCOutputFieldValueFragment, { ...props })));
7
9
  }
@@ -1,4 +1,6 @@
1
1
  import React, {} from 'react';
2
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
2
3
  export function UCAutoExecLoader() {
3
- return React.createElement("div", null, "...");
4
+ const { autoExecLoader } = useStyleContext();
5
+ return (React.createElement("div", { className: autoExecLoader?.className, style: autoExecLoader?.style }, "..."));
4
6
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
3
  import type { UCEntrypointTouchableProps } from '../lib/react/touchable.js';
4
- export declare function UCEntrypointTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ className, path, wording, }: UCEntrypointTouchableProps<I, OPI0, OPI1>): ReactElement;
4
+ export declare function UCEntrypointTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ path, wording }: UCEntrypointTouchableProps<I, OPI0, OPI1>): ReactElement;
@@ -1,4 +1,6 @@
1
1
  import React, {} from 'react';
2
- export function UCEntrypointTouchable({ className, path, wording, }) {
3
- return (React.createElement("a", { className: className, href: path, title: wording.desc ?? undefined }, wording.label));
2
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
+ export function UCEntrypointTouchable({ path, wording }) {
4
+ const { entrypointTouchable } = useStyleContext();
5
+ return (React.createElement("a", { className: entrypointTouchable?.className, href: path, style: entrypointTouchable?.style, title: wording.desc ?? undefined }, wording.label));
4
6
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
3
  import type { UCExecTouchableProps } from '../lib/react/touchable.js';
4
- export declare function UCExecTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ className, disabled, execState, onSubmit, uc, }: UCExecTouchableProps<I, OPI0, OPI1>): ReactElement;
4
+ export declare function UCExecTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState, onSubmit, uc, }: UCExecTouchableProps<I, OPI0, OPI1>): ReactElement;
@@ -1,7 +1,9 @@
1
1
  import React, {} from 'react';
2
2
  import { useDIContext } from '../lib/react/DIContextProvider.js';
3
- export function UCExecTouchable({ className, disabled, execState, onSubmit, uc, }) {
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
+ export function UCExecTouchable({ disabled, execState, onSubmit, uc, }) {
4
5
  const { wordingManager } = useDIContext();
6
+ const { execTouchable } = useStyleContext();
5
7
  const label = wordingManager.ucISubmit(uc.def, execState);
6
- return (React.createElement("button", { className: className, disabled: disabled, onClick: onSubmit, type: "button" }, label));
8
+ return (React.createElement("button", { className: execTouchable?.className, disabled: disabled, onClick: onSubmit, style: execTouchable?.style, type: "button" }, label));
7
9
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
3
  import type { UCFormProps } from '../lib/react/form.js';
4
- export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ className, clearAfterExec, disabled, execState, onChange, onSubmit: onSubmitBase, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
4
+ export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ clearAfterExec, disabled, execState, onChange, onSubmit: onSubmitBase, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
@@ -1,7 +1,9 @@
1
1
  import React, { useRef } from 'react';
2
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
2
3
  import { UCFormField } from './UCFormField.js';
3
4
  import { UCFormSubmitControl } from './UCFormSubmitControl.js';
4
- export function UCForm({ className, clearAfterExec, disabled, execState, onChange, onSubmit: onSubmitBase, uc, }) {
5
+ export function UCForm({ clearAfterExec, disabled, execState, onChange, onSubmit: onSubmitBase, uc, }) {
6
+ const { form } = useStyleContext();
5
7
  const formRef = useRef(null);
6
8
  const onSubmit = async (e) => {
7
9
  e.preventDefault();
@@ -10,7 +12,7 @@ export function UCForm({ className, clearAfterExec, disabled, execState, onChang
10
12
  formRef.current?.reset();
11
13
  }
12
14
  };
13
- return (React.createElement("form", { className: className, onSubmit: onSubmit, ref: formRef },
15
+ return (React.createElement("form", { className: form?.className, onSubmit: onSubmit, ref: formRef, style: form?.style },
14
16
  uc.inputFieldsForForm().map((f) => (React.createElement(UCFormField, { key: f.key, disabled: disabled, execState: execState, f: f, onChange: onChange }))),
15
17
  React.createElement(UCFormSubmitControl, { execState: execState, disabled: disabled, uc: uc })));
16
18
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { DataType } from '../../dt/index.js';
3
3
  import { type UCFormFieldProps } from '../lib/react/form.js';
4
- export declare function UCFormField<T extends DataType>({ className, disabled, execState, f, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
4
+ export declare function UCFormField<T extends DataType>({ disabled, execState, f, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
@@ -1,19 +1,21 @@
1
1
  import React, { useState } from 'react';
2
2
  import { useDIContext } from '../lib/react/DIContextProvider.js';
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
4
  import { UC_FORM_FIELD_ELEMENTS, validateFormField, } from '../lib/react/form.js';
4
5
  import { UCFormFieldControl } from './UCFormFieldControl.js';
5
6
  import { UCFormFieldDesc } from './UCFormFieldDesc.js';
6
7
  import { UCFormFieldErr } from './UCFormFieldErr.js';
7
8
  import { UCFormFieldLabel } from './UCFormFieldLabel.js';
8
- export function UCFormField({ className, disabled, execState, f, onChange: onChangeBase, only, }) {
9
+ export function UCFormField({ disabled, execState, f, onChange: onChangeBase, only, }) {
9
10
  const { i18nManager } = useDIContext();
11
+ const { formField } = useStyleContext();
10
12
  const [errMsg, setErrMsg] = useState(null);
11
13
  const onChange = (f, op, v) => {
12
14
  setErrMsg(validateFormField(i18nManager, f, v));
13
15
  onChangeBase(f, op, v);
14
16
  };
15
17
  const elements = only ?? UC_FORM_FIELD_ELEMENTS;
16
- return (React.createElement("div", { className: className },
18
+ return (React.createElement("div", { className: formField?.className, style: formField?.style },
17
19
  elements.includes('label') && React.createElement(UCFormFieldLabel, { f: f }),
18
20
  elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })),
19
21
  elements.includes('err') && errMsg && (React.createElement(UCFormFieldErr, { errMsg: errMsg })),
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
- import type { DataType } from '../../dt/index.js';
2
+ import { type DataType } from '../../dt/index.js';
3
3
  import type { UCFormFieldControlProps } from '../lib/react/form.js';
4
- export declare function UCFormFieldControl<T extends DataType>({ className, errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
4
+ export declare function UCFormFieldControl<T extends DataType>({ disabled, errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
@@ -1,11 +1,25 @@
1
1
  import React, {} from 'react';
2
+ import { TBoolean } from '../../dt/index.js';
2
3
  import { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.js';
4
+ import { styleDef, useStyleContext, } from '../lib/react/StyleContextProvider.js';
3
5
  import { htmlInputDef } from '../lib/web/input.js';
4
6
  const CHECKED_FIELD_TYPES = ['checkbox', 'radio'];
5
7
  const FILE_FIELD_TYPES = ['file'];
6
8
  const MULTIPLE_VALUES_SEPARATOR = ',';
7
- export function UCFormFieldControl({ className, errMsg = null, execState, f, onChange: onChangeBase, }) {
8
- const attrs = htmlInputDef(f, execState, errMsg, className);
9
+ // TODO : Split this into smaller components
10
+ export function UCFormFieldControl({ disabled, errMsg = null, execState, f, onChange: onChangeBase, }) {
11
+ const { formFieldControl, renderFormFieldControl } = useStyleContext();
12
+ const component = renderFormFieldControl?.({
13
+ disabled,
14
+ errMsg,
15
+ execState,
16
+ f,
17
+ onChange: onChangeBase,
18
+ });
19
+ if (component) {
20
+ return component;
21
+ }
22
+ const attrs = htmlInputDef(f, disabled, errMsg);
9
23
  const onChange = (e) => {
10
24
  const target = e.currentTarget;
11
25
  const type = target.type;
@@ -36,16 +50,23 @@ export function UCFormFieldControl({ className, errMsg = null, execState, f, onC
36
50
  const defaultChecked = attrs.internal?.checked;
37
51
  const defaultValue = attrs.internal?.value;
38
52
  if (attrs.internal?.multiline) {
39
- return (React.createElement("textarea", { ...attrs.spec, defaultValue: defaultValue, onChange: onChange }));
53
+ const { className, style } = styleDef(formFieldControl, 'textarea', 'default');
54
+ return (React.createElement("textarea", { ...attrs.spec, className: className, defaultValue: defaultValue, onChange: onChange, style: style }));
40
55
  }
41
56
  const { type } = f.def;
57
+ if (type instanceof TBoolean) {
58
+ const { className, style } = styleDef(formFieldControl, 'checkbox');
59
+ return (React.createElement("input", { ...attrs.spec, className: className, defaultChecked: defaultChecked, defaultValue: defaultValue, onChange: onChange, style: style }));
60
+ }
42
61
  const options = type.getOptions();
43
62
  if (options) {
44
63
  // TODO : Handle type.hasStrictOptions() => display an input text alongside the select
45
64
  // TODO : Consider using a radio and/or checkbox and/or selectable buttons when the options count < X
46
- return (React.createElement("select", { ...attrs.spec, defaultValue: defaultValue, onChange: onChange },
65
+ const { className, style } = styleDef(formFieldControl, 'select', 'default');
66
+ return (React.createElement("select", { ...attrs.spec, className: className, defaultValue: defaultValue, onChange: onChange, style: style },
47
67
  React.createElement("option", null),
48
68
  options.map((o) => (React.createElement("option", { key: o.value.toString(), value: o.value.toString() }, o.label)))));
49
69
  }
50
- return (React.createElement("input", { ...attrs.spec, defaultChecked: defaultChecked, defaultValue: defaultValue, onChange: onChange }));
70
+ const { className, style } = styleDef(formFieldControl, 'input', 'default');
71
+ return (React.createElement("input", { ...attrs.spec, className: className, defaultChecked: defaultChecked, defaultValue: defaultValue, onChange: onChange, style: style }));
51
72
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { DataType } from '../../dt/index.js';
3
3
  import type { UCFormFieldDescProps } from '../lib/react/form.js';
4
- export declare function UCFormFieldDesc<T extends DataType>({ className, f, }: UCFormFieldDescProps<T>): ReactElement | null;
4
+ export declare function UCFormFieldDesc<T extends DataType>({ f, }: UCFormFieldDescProps<T>): ReactElement | null;
@@ -1,10 +1,12 @@
1
1
  import React, {} from 'react';
2
2
  import { useDIContext } from '../lib/react/DIContextProvider.js';
3
- export function UCFormFieldDesc({ className, f, }) {
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
+ export function UCFormFieldDesc({ f, }) {
4
5
  const { wordingManager } = useDIContext();
6
+ const { formFieldDesc } = useStyleContext();
5
7
  const { desc } = wordingManager.ucif(f);
6
8
  if (!desc) {
7
9
  return null;
8
10
  }
9
- return React.createElement("div", { className: className }, desc);
11
+ return (React.createElement("div", { className: formFieldDesc?.className, style: formFieldDesc?.style }, desc));
10
12
  }
@@ -1,3 +1,3 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UCFormFieldErrProps } from '../lib/react/form.js';
3
- export declare function UCFormFieldErr({ className, errMsg, }: UCFormFieldErrProps): ReactElement;
3
+ export declare function UCFormFieldErr({ errMsg }: UCFormFieldErrProps): ReactElement;
@@ -1,4 +1,6 @@
1
1
  import React, {} from 'react';
2
- export function UCFormFieldErr({ className, errMsg, }) {
3
- return React.createElement("div", { className: className }, errMsg);
2
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
3
+ export function UCFormFieldErr({ errMsg }) {
4
+ const { formFieldErr } = useStyleContext();
5
+ return (React.createElement("div", { className: formFieldErr?.className, style: formFieldErr?.style }, errMsg));
4
6
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { DataType } from '../../dt/index.js';
3
3
  import type { UCFormFieldLabelProps } from '../lib/react/form.js';
4
- export declare function UCFormFieldLabel<T extends DataType>({ className, f, }: UCFormFieldLabelProps<T>): ReactElement;
4
+ export declare function UCFormFieldLabel<T extends DataType>({ f, }: UCFormFieldLabelProps<T>): ReactElement;
@@ -1,8 +1,13 @@
1
1
  import React, {} from 'react';
2
- import { ucifId } from '../../uc/index.js';
2
+ import { ucifId, ucifIsMandatory } from '../../uc/index.js';
3
3
  import { useDIContext } from '../lib/react/DIContextProvider.js';
4
- export function UCFormFieldLabel({ className, f, }) {
4
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
5
+ export function UCFormFieldLabel({ f, }) {
5
6
  const { wordingManager } = useDIContext();
7
+ const { formFieldLabel } = useStyleContext();
6
8
  const { label } = wordingManager.ucif(f);
7
- return (React.createElement("label", { className: className, htmlFor: ucifId(f.key) }, label));
9
+ const mandatory = ucifIsMandatory(f.def);
10
+ return (React.createElement("label", { className: formFieldLabel?.className, htmlFor: ucifId(f.key), style: formFieldLabel?.style },
11
+ label,
12
+ mandatory && ' *'));
8
13
  }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
3
  import type { UCFormSubmitControlProps } from '../lib/react/form.js';
4
- export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ className, execState, disabled, uc, }: UCFormSubmitControlProps<I, OPI0, OPI1>): ReactElement;
4
+ export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, uc, }: UCFormSubmitControlProps<I, OPI0, OPI1>): ReactElement;
@@ -1,6 +1,8 @@
1
1
  import React, {} from 'react';
2
2
  import { useDIContext } from '../lib/react/DIContextProvider.js';
3
- export function UCFormSubmitControl({ className, execState, disabled, uc, }) {
3
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
4
+ export function UCFormSubmitControl({ execState, disabled, uc, }) {
4
5
  const { wordingManager } = useDIContext();
5
- return (React.createElement("input", { className: className, disabled: disabled, type: "submit", value: wordingManager.ucISubmit(uc.def, execState) }));
6
+ const { formSubmitControl } = useStyleContext();
7
+ return (React.createElement("input", { className: formSubmitControl?.className, disabled: disabled, style: formSubmitControl?.style, type: "submit", value: wordingManager.ucISubmit(uc.def, execState) }));
6
8
  }
@@ -2,4 +2,4 @@ import { type ReactElement } from 'react';
2
2
  import type { DataType } from '../../dt/index.js';
3
3
  import type { UCOPIBase } from '../../uc/index.js';
4
4
  import { type Props } from '../lib/react/UCOutputFieldValueFragment.js';
5
- export declare function UCOutputFieldValue<OPI extends UCOPIBase, T extends DataType>({ className, ...propsWithoutClassName }: Props<OPI, T>): ReactElement;
5
+ export declare function UCOutputFieldValue<OPI extends UCOPIBase, T extends DataType>(props: Props<OPI, T>): ReactElement;
@@ -1,6 +1,8 @@
1
1
  import React, {} from 'react';
2
+ import { useStyleContext } from '../lib/react/StyleContextProvider.js';
2
3
  import { UCOutputFieldValueFragment, } from '../lib/react/UCOutputFieldValueFragment.js';
3
- export function UCOutputFieldValue({ className, ...propsWithoutClassName }) {
4
- return (React.createElement("span", { className: className },
5
- React.createElement(UCOutputFieldValueFragment, { ...propsWithoutClassName })));
4
+ export function UCOutputFieldValue(props) {
5
+ const { outputFieldValue } = useStyleContext();
6
+ return (React.createElement("span", { className: outputFieldValue?.className, style: outputFieldValue?.style },
7
+ React.createElement(UCOutputFieldValueFragment, { ...props })));
6
8
  }
@@ -0,0 +1,10 @@
1
+ import { WordingManager } from '../../i18n/index.js';
2
+ import type { UCClientConfirmManager } from '../client.js';
3
+ import type { UCDef } from '../def.js';
4
+ import type { UCInput } from '../input.js';
5
+ import type { UCOPIBase } from '../opi.js';
6
+ export declare class RNUCClientConfirmManager implements UCClientConfirmManager {
7
+ private wordingManager;
8
+ constructor(wordingManager: WordingManager);
9
+ exec<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(ucd: UCDef<I, OPI0, OPI1>): Promise<boolean>;
10
+ }
@@ -0,0 +1,44 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from 'inversify';
14
+ import { Alert } from 'react-native';
15
+ import { WordingManager } from '../../i18n/index.js';
16
+ let RNUCClientConfirmManager = class RNUCClientConfirmManager {
17
+ wordingManager;
18
+ constructor(wordingManager) {
19
+ this.wordingManager = wordingManager;
20
+ }
21
+ async exec(ucd) {
22
+ const { cancel, confirm, message, title } = this.wordingManager.ucClientConfirm(ucd);
23
+ return new Promise((resolve) => {
24
+ Alert.alert(title, message ?? undefined, [
25
+ {
26
+ onPress: () => resolve(true),
27
+ style: 'destructive',
28
+ text: confirm,
29
+ },
30
+ {
31
+ onPress: () => resolve(false),
32
+ style: 'cancel',
33
+ text: cancel,
34
+ },
35
+ ]);
36
+ });
37
+ }
38
+ };
39
+ RNUCClientConfirmManager = __decorate([
40
+ injectable(),
41
+ __param(0, inject(WordingManager)),
42
+ __metadata("design:paramtypes", [WordingManager])
43
+ ], RNUCClientConfirmManager);
44
+ export { RNUCClientConfirmManager };
@@ -1,5 +1,10 @@
1
1
  import { BufferLibBufferManager } from '../../std/impl/BufferLibBufferManager.js';
2
+ import { RNUCClientConfirmManager } from '../../uc/impl/RNUCClientConfirmManager.js';
2
3
  export function bindRN(container) {
3
4
  // std
4
5
  container.bind('BufferManager').to(BufferLibBufferManager);
6
+ // uc
7
+ container
8
+ .rebindSync('UCClientConfirmManager')
9
+ .to(RNUCClientConfirmManager);
5
10
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmodulor",
3
3
  "description": "A TypeScript library to create platform-agnostic applications",
4
- "version": "0.15.0",
4
+ "version": "0.17.0",
5
5
  "license": "LGPL-3.0",
6
6
  "author": "Chafik H'nini <chafik.hnini@gmail.com>",
7
7
  "homepage": "https://libmodulor.c100k.eu",
@@ -81,8 +81,8 @@
81
81
  "@biomejs/biome": "^1.9.4"
82
82
  },
83
83
  "peerDependencies": {
84
- "@hono/node-server": "^1.14.1",
85
- "@modelcontextprotocol/sdk": "^1.11.4",
84
+ "@hono/node-server": "^1.14.2",
85
+ "@modelcontextprotocol/sdk": "^1.12.0",
86
86
  "@stricli/core": "^1.1.2",
87
87
  "buffer": "^6.0.3",
88
88
  "cookie-parser": "^1.4.7",
@@ -103,7 +103,7 @@
103
103
  "sqlite3": "^5.1.7",
104
104
  "typescript": "^5.8.3",
105
105
  "vite": "^6.3.5",
106
- "vitest": "^3.1.3"
106
+ "vitest": "^3.1.4"
107
107
  },
108
108
  "peerDependenciesMeta": {
109
109
  "@hono/node-server": {
@@ -0,0 +1,9 @@
1
+ onlyBuiltDependencies:
2
+ - '@biomejs/biome'
3
+ - esbuild
4
+ - sharp
5
+ - sqlite3
6
+ packages:
7
+ - docs-fd
8
+ - examples/basic
9
+ - examples/supertrader