dara-core 1.16.22__py3-none-any.whl → 1.16.23__py3-none-any.whl

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.
dara/core/definitions.py CHANGED
@@ -70,6 +70,11 @@ DEFAULT_ERROR_TITLE = 'Unexpected error occurred'
70
70
  DEFAULT_ERROR_DESCRIPTION = 'Try again or contact the application owner'
71
71
 
72
72
 
73
+ def _kebab_to_camel(string: str):
74
+ chunks = string.split('-')
75
+ return chunks[0] + ''.join([chunk[0].upper() + chunk[1:].lower() for chunk in chunks[1:]])
76
+
77
+
73
78
  class ErrorHandlingConfig(BaseModel):
74
79
  title: str = DEFAULT_ERROR_TITLE
75
80
  """Title to display in the error boundary"""
@@ -77,8 +82,27 @@ class ErrorHandlingConfig(BaseModel):
77
82
  description: str = DEFAULT_ERROR_DESCRIPTION
78
83
  """Description to display in the error boundary"""
79
84
 
80
- raw_css: Optional[Union[CSSProperties, dict, str]] = None
81
- """Raw styling to apply to the displayed error boundary"""
85
+ raw_css: Optional[Any] = None
86
+ """
87
+ Raw styling to apply to the displayed error boundary.
88
+ Accepts a CSSProperties, dict, str, or NonDataVariable.
89
+ """
90
+
91
+ @field_validator('raw_css', mode='before')
92
+ @classmethod
93
+ def validate_raw_css(cls, value):
94
+ from dara.core.interactivity.non_data_variable import NonDataVariable
95
+
96
+ if isinstance(value, str):
97
+ return str
98
+ if isinstance(value, dict):
99
+ return {_kebab_to_camel(k): v for k, v in value.items()}
100
+ if isinstance(value, NonDataVariable):
101
+ return value
102
+ if isinstance(value, CSSProperties):
103
+ return value
104
+
105
+ raise ValueError(f'raw_css must be a CSSProperties, dict, str, or NonDataVariable, got {type(value)}')
82
106
 
83
107
  def model_dump(self, *args, **kwargs):
84
108
  result = super().model_dump(*args, **kwargs)
@@ -120,14 +144,15 @@ class ComponentInstance(BaseModel):
120
144
  required_routes: ClassVar[List[ApiRoute]] = []
121
145
  """List of routes the component depends on. Will be implicitly added to the app if this component is used"""
122
146
 
123
- raw_css: Optional[Union[CSSProperties, dict, str]] = None
147
+ raw_css: Optional[Any] = None
124
148
  """
125
149
  Raw styling to apply to the component.
126
- Can be an dict/CSSProperties instance representing the `styles` tag, or a string injected directly into the CSS of the wrapping component.
150
+ Can be an dict/CSSProperties instance representing the `styles` tag, a string injected directly into the CSS of the wrapping component,
151
+ or a NonDataVariable resoling to either of the above.
127
152
 
128
153
  ```python
129
154
 
130
- from dara.core import CSSProperties
155
+ from dara.core import CSSProperties, Variable
131
156
 
132
157
  # `style` - use the class for autocompletion/typesense
133
158
  Stack(..., raw_css=CSSProperties(maxWidth='100px'))
@@ -140,6 +165,9 @@ class ComponentInstance(BaseModel):
140
165
  max-width: 100px;
141
166
  \"\"\")
142
167
 
168
+ css_var = Variable('color: red;')
169
+ Stack(..., raw_css=css_var)
170
+
143
171
  ```
144
172
  """
145
173
 
@@ -173,17 +201,23 @@ class ComponentInstance(BaseModel):
173
201
 
174
202
  @field_validator('raw_css', mode='before')
175
203
  @classmethod
176
- def parse_css(cls, css: Optional[Union[CSSProperties, dict, str]]):
204
+ def parse_css(cls, css: Optional[Any]):
205
+ from dara.core.interactivity.non_data_variable import NonDataVariable
206
+
177
207
  # If it's a plain dict, change kebab case to camel case
178
208
  if isinstance(css, dict):
209
+ return {_kebab_to_camel(k): v for k, v in css.items()}
210
+
211
+ if isinstance(css, NonDataVariable):
212
+ return css
179
213
 
180
- def kebab_to_camel(string: str):
181
- chunks = string.split('-')
182
- return chunks[0] + ''.join([chunk[0].upper() + chunk[1:].lower() for chunk in chunks[1:]])
214
+ if isinstance(css, CSSProperties):
215
+ return css
183
216
 
184
- return {kebab_to_camel(k): v for k, v in css.items()}
217
+ if isinstance(css, str):
218
+ return css
185
219
 
186
- return css
220
+ raise ValueError(f'raw_css must be a CSSProperties, dict, str, or NonDataVariable, got {type(css)}')
187
221
 
188
222
  @classmethod
189
223
  def isinstance(cls, obj: Any) -> bool:
@@ -399,7 +433,6 @@ class BaseFallback(StyledComponentInstance):
399
433
 
400
434
  ComponentInstance.model_rebuild()
401
435
 
402
-
403
436
  ComponentInstanceType = Union[ComponentInstance, Callable[..., ComponentInstance]]
404
437
 
405
438
 
@@ -17386,6 +17386,62 @@ var __privateWrapper = (obj, member, setter, getter) => ({
17386
17386
  var _baseIteratee = baseIteratee$3;
17387
17387
  var e$2 = "object" == typeof navigator ? navigator.platform : "";
17388
17388
  /Mac|iPod|iPhone|iPad/.test(e$2);
17389
+ function useIMEEnter({ onKeyDown: userKeyDown, onKeyUp: userKeyUp, onCompositionStart: userCompStart, onCompositionEnd: userCompEnd }) {
17390
+ const isComposingRef = React.useRef(false);
17391
+ const justEndedRef = React.useRef(false);
17392
+ const handleCompositionStart = React.useCallback((e2) => {
17393
+ isComposingRef.current = true;
17394
+ userCompStart === null || userCompStart === void 0 ? void 0 : userCompStart(e2);
17395
+ }, [userCompStart]);
17396
+ const handleCompositionEnd = React.useCallback((e2) => {
17397
+ isComposingRef.current = false;
17398
+ justEndedRef.current = true;
17399
+ userCompEnd === null || userCompEnd === void 0 ? void 0 : userCompEnd(e2);
17400
+ }, [userCompEnd]);
17401
+ const handleKeyDownCapture = React.useCallback((e2) => {
17402
+ if (isComposingRef.current) {
17403
+ e2.preventDefault();
17404
+ e2.stopPropagation();
17405
+ return;
17406
+ }
17407
+ if (justEndedRef.current) {
17408
+ if (e2.which === 229) {
17409
+ e2.preventDefault();
17410
+ e2.stopPropagation();
17411
+ return;
17412
+ }
17413
+ justEndedRef.current = false;
17414
+ }
17415
+ }, []);
17416
+ const handleKeyDown = React.useCallback((e2) => {
17417
+ if (isComposingRef.current) {
17418
+ return;
17419
+ }
17420
+ userKeyDown === null || userKeyDown === void 0 ? void 0 : userKeyDown(e2);
17421
+ }, [userKeyDown]);
17422
+ const handleKeyUpCapture = React.useCallback((e2) => {
17423
+ if (isComposingRef.current || justEndedRef.current) {
17424
+ justEndedRef.current = false;
17425
+ e2.preventDefault();
17426
+ e2.stopPropagation();
17427
+ }
17428
+ }, []);
17429
+ const handleKeyUp = React.useCallback((e2) => {
17430
+ if (isComposingRef.current || justEndedRef.current) {
17431
+ justEndedRef.current = false;
17432
+ return;
17433
+ }
17434
+ userKeyUp === null || userKeyUp === void 0 ? void 0 : userKeyUp(e2);
17435
+ }, [userKeyUp]);
17436
+ return {
17437
+ onCompositionStart: handleCompositionStart,
17438
+ onCompositionEnd: handleCompositionEnd,
17439
+ onKeyDownCapture: handleKeyDownCapture,
17440
+ onKeyDown: handleKeyDown,
17441
+ onKeyUpCapture: handleKeyUpCapture,
17442
+ onKeyUp: handleKeyUp
17443
+ };
17444
+ }
17389
17445
  globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
17390
17446
  function adopt(value) {
17391
17447
  return value instanceof P ? value : new P(function(resolve) {
@@ -26380,7 +26436,14 @@ var __privateWrapper = (obj, member, setter, getter) => ({
26380
26436
  onComplete();
26381
26437
  }
26382
26438
  };
26383
- return jsxRuntime.exports.jsxs(InputWrapper$3, { className, style, children: [jsxRuntime.exports.jsx(PrimaryInput, Object.assign({}, rest, { defaultValue: initialValue, isErrored: !!errorMsg, onChange: handleChange, onKeyDown: handleKeyDown, ref, type, min: minValue, max: maxValue })), errorMsg && jsxRuntime.exports.jsx(ErrorMessage$1, { children: errorMsg })] });
26439
+ const handlers = useIMEEnter({
26440
+ onKeyDown: handleKeyDown,
26441
+ onKeyUp: rest.onKeyUp,
26442
+ onCompositionStart: rest.onCompositionStart,
26443
+ onCompositionEnd: rest.onCompositionEnd
26444
+ });
26445
+ const spreadProps = Object.assign(Object.assign({}, rest), handlers);
26446
+ return jsxRuntime.exports.jsxs(InputWrapper$3, { className, style, children: [jsxRuntime.exports.jsx(PrimaryInput, Object.assign({}, spreadProps, { defaultValue: initialValue, isErrored: !!errorMsg, onChange: handleChange, ref, type, min: minValue, max: maxValue })), errorMsg && jsxRuntime.exports.jsx(ErrorMessage$1, { children: errorMsg })] });
26384
26447
  });
26385
26448
  Input$1.displayName = "Input";
26386
26449
  const Wrapper$7 = styled__default.default.div`
@@ -51842,244 +51905,6 @@ Inferred class string: "${iconClasses}."`
51842
51905
  return /* @__PURE__ */ React__default.default.createElement(Icon, { ...props, className: `${String((_a = props.className) != null ? _a : "")} ${iconClasses}` });
51843
51906
  };
51844
51907
  }
51845
- function flexStyles(props, displayCtx2, useDisplayContext) {
51846
- let flexBasis = props.basis;
51847
- let flexShrink = props.shrink;
51848
- let flexGrow = props.grow;
51849
- if (useDisplayContext) {
51850
- if (props.width && displayCtx2.direction === "horizontal") {
51851
- flexBasis != null ? flexBasis : flexBasis = props.width;
51852
- flexShrink != null ? flexShrink : flexShrink = "0";
51853
- flexGrow != null ? flexGrow : flexGrow = "0";
51854
- }
51855
- if (props.height && displayCtx2.direction === "vertical") {
51856
- flexBasis != null ? flexBasis : flexBasis = props.height;
51857
- flexShrink != null ? flexShrink : flexShrink = "0";
51858
- flexGrow != null ? flexGrow : flexGrow = "0";
51859
- }
51860
- }
51861
- if (props.hug || props.hug !== false && displayCtx2.hug) {
51862
- flexBasis != null ? flexBasis : flexBasis = "content";
51863
- flexShrink != null ? flexShrink : flexShrink = "1";
51864
- flexGrow != null ? flexGrow : flexGrow = "0";
51865
- }
51866
- return { flexBasis, flexGrow, flexShrink };
51867
- }
51868
- function parseRawCss(rawCss) {
51869
- const isRawObject = typeof rawCss === "object" && rawCss !== null && rawCss !== void 0;
51870
- const componentCss = !isRawObject && typeof rawCss === "string" ? rawCss : "";
51871
- const styles2 = isRawObject ? rawCss : {};
51872
- return [styles2, componentCss];
51873
- }
51874
- function useComponentStyles(props, useDisplayContext = true) {
51875
- const [rawStyles, rawCss] = parseRawCss(props.raw_css);
51876
- const displayCtx$1 = React.useContext(displayCtx);
51877
- const flexProps = flexStyles(props, displayCtx$1, useDisplayContext);
51878
- const styles2 = React.useMemo(() => {
51879
- var _a;
51880
- const stylesObj = {
51881
- backgroundColor: props.background,
51882
- border: props.border,
51883
- borderRadius: props.border_radius,
51884
- color: props.color,
51885
- fontFamily: props.font,
51886
- fontSize: props.font_size,
51887
- fontStyle: props.italic ? "italic" : "normal",
51888
- fontWeight: props.bold ? "bold" : "normal",
51889
- gap: props.gap,
51890
- height: props.height,
51891
- margin: props.margin,
51892
- maxHeight: props.max_height,
51893
- maxWidth: props.max_width,
51894
- minHeight: props.min_height,
51895
- minWidth: props.min_width,
51896
- overflow: props.overflow,
51897
- padding: props.padding,
51898
- position: props.position,
51899
- textDecoration: props.underline ? "underline" : "none",
51900
- width: props.width,
51901
- ...flexProps,
51902
- ...rawStyles,
51903
- ...(_a = props.style) != null ? _a : {}
51904
- };
51905
- return Object.fromEntries(Object.entries(stylesObj).filter(([, v2]) => v2 !== null && v2 !== void 0));
51906
- }, [useDeepCompare(props)]);
51907
- return [styles2, rawCss];
51908
- }
51909
- function useUrlSync(options) {
51910
- const urlSerializer = React.useCallback((val) => {
51911
- if (val === void 0 || val === null) {
51912
- return "";
51913
- }
51914
- if (["string", "number", "boolean"].includes(typeof val)) {
51915
- return String(val);
51916
- }
51917
- return JSON.stringify(val);
51918
- }, []);
51919
- const urlDeserializer = React.useCallback((val) => {
51920
- if (val === "") {
51921
- return void 0;
51922
- }
51923
- try {
51924
- return JSON.parse(val);
51925
- } catch {
51926
- return val;
51927
- }
51928
- }, []);
51929
- const listenChangeURL = React.useCallback((handler) => {
51930
- const unregister = options.history.listen(() => {
51931
- handler();
51932
- });
51933
- return () => unregister();
51934
- }, []);
51935
- const memoryOptions = {
51936
- getURL: () => {
51937
- return window.location.origin + options.history.location.pathname + options.history.location.search;
51938
- },
51939
- pushURL: (url) => {
51940
- options.history.push(url.replace(window.location.origin, ""));
51941
- },
51942
- replaceURL: (url) => {
51943
- options.history.replace(url.replace(window.location.origin, ""));
51944
- }
51945
- };
51946
- return {
51947
- browserInterface: {
51948
- listenChangeURL,
51949
- ...options.memory_TEST ? memoryOptions : {}
51950
- },
51951
- deserialize: urlDeserializer,
51952
- location: { part: "queryParams" },
51953
- serialize: urlSerializer
51954
- };
51955
- }
51956
- const Wrapper$2 = styled__default.default.div`
51957
- display: flex;
51958
- align-items: center;
51959
- justify-content: center;
51960
-
51961
- width: 100%;
51962
- height: 100%;
51963
- `;
51964
- const FlashingDots = styled__default.default.div`
51965
- position: relative;
51966
-
51967
- width: 10px;
51968
- height: 10px;
51969
-
51970
- color: ${(props) => props.theme.colors.grey4};
51971
-
51972
- background-color: ${(props) => props.theme.colors.grey4};
51973
- border-radius: 5px;
51974
-
51975
- animation: dot-flashing 1s infinite linear alternate;
51976
- animation-delay: 0.5s;
51977
-
51978
- &::before,
51979
- &::after {
51980
- content: '';
51981
- position: absolute;
51982
- top: 0;
51983
- display: inline-block;
51984
- }
51985
-
51986
- &::before {
51987
- left: -15px;
51988
-
51989
- width: 10px;
51990
- height: 10px;
51991
-
51992
- color: ${(props) => props.theme.colors.grey4};
51993
-
51994
- background-color: ${(props) => props.theme.colors.grey4};
51995
- border-radius: 5px;
51996
-
51997
- animation: dot-flashing 1s infinite alternate;
51998
- animation-delay: 0s;
51999
- }
52000
-
52001
- &::after {
52002
- left: 15px;
52003
-
52004
- width: 10px;
52005
- height: 10px;
52006
-
52007
- color: ${(props) => props.theme.colors.grey4};
52008
-
52009
- background-color: ${(props) => props.theme.colors.grey4};
52010
- border-radius: 5px;
52011
-
52012
- animation: dot-flashing 1s infinite alternate;
52013
- animation-delay: 1s;
52014
- }
52015
-
52016
- @keyframes dot-flashing {
52017
- 0% {
52018
- background-color: ${(props) => props.theme.colors.grey4};
52019
- }
52020
-
52021
- 50%,
52022
- 100% {
52023
- background-color: ${(props) => props.theme.colors.grey3};
52024
- }
52025
- }
52026
- `;
52027
- function Dots(props) {
52028
- return /* @__PURE__ */ React__default.default.createElement(Wrapper$2, { className: props.className, style: props.style }, /* @__PURE__ */ React__default.default.createElement(FlashingDots, { "data-testid": "LOADING" }));
52029
- }
52030
- const StyledDots$1 = injectCss(Dots);
52031
- function DefaultFallback(props) {
52032
- const [style, css2] = useComponentStyles(props);
52033
- return /* @__PURE__ */ React__default.default.createElement(StyledDots$1, { $rawCss: css2, style });
52034
- }
52035
- const Center = styled__default.default.div`
52036
- overflow: hidden;
52037
- display: flex;
52038
- flex-direction: column;
52039
- align-items: center;
52040
- justify-content: center;
52041
-
52042
- width: 100%;
52043
- height: 100%;
52044
-
52045
- background: ${(props) => props.colored ? props.theme.colors.blue1 : ""};
52046
- `;
52047
- const CenteredDivWithGap = styled__default.default(Center)`
52048
- gap: 0.6rem;
52049
- margin: 10px;
52050
- text-align: center;
52051
- `;
52052
- const errorMessages = {
52053
- "403": {
52054
- description: "You are not authorised to access this application. Please contact the application owner to enable access.",
52055
- styling: "error",
52056
- title: "We were not able to authenticate you"
52057
- },
52058
- default: {
52059
- description: "Your login session may have expired. Try again.",
52060
- styling: "primary",
52061
- title: "We were not able to authenticate you"
52062
- }
52063
- };
52064
- function ErrorPage() {
52065
- const { search } = useLocation();
52066
- const query = React.useMemo(() => new URLSearchParams(search), [search]);
52067
- const code = query.get("code");
52068
- const errorConfig = code && errorMessages[code] || errorMessages.default;
52069
- return /* @__PURE__ */ React__default.default.createElement(CenteredDivWithGap, null, /* @__PURE__ */ React__default.default.createElement("h1", null, errorConfig.title), /* @__PURE__ */ React__default.default.createElement("p", null, errorConfig.description), /* @__PURE__ */ React__default.default.createElement(Button$1, { href: "/login", styling: errorConfig.styling }, "Retry"));
52070
- }
52071
- function onTokenChange(cb) {
52072
- return store.subscribe(getTokenKey(), cb);
52073
- }
52074
- function getSessionToken() {
52075
- return store.getValueSync(getTokenKey());
52076
- }
52077
- function setSessionToken(token) {
52078
- store.setValue(getTokenKey(), token);
52079
- }
52080
- function useSessionToken() {
52081
- return React__namespace.useSyncExternalStore(onTokenChange, getSessionToken);
52082
- }
52083
51908
  class EventBus {
52084
51909
  constructor(parentBus) {
52085
51910
  __privateAdd(this, _events$, new Subject());
@@ -52112,19 +51937,6 @@ Inferred class string: "${iconClasses}."`
52112
51937
  }, [bus, onEvent]);
52113
51938
  return /* @__PURE__ */ React__namespace.createElement(EventBusContext.Provider, { value: bus }, children);
52114
51939
  }
52115
- function useActionRegistry() {
52116
- const { actionRegistry: actions } = React.useContext(registriesCtx);
52117
- const get2 = React.useCallback(
52118
- (impl) => {
52119
- if (actions && actions[impl.name]) {
52120
- return actions[impl.name];
52121
- }
52122
- throw new Error(`Attempted to load an action (${impl.name}) that is not in the registry`);
52123
- },
52124
- [actions]
52125
- );
52126
- return React.useMemo(() => ({ get: get2 }), [get2]);
52127
- }
52128
51940
  const _StateSynchronizer = class {
52129
51941
  constructor() {
52130
51942
  __privateAdd(this, _observers, /* @__PURE__ */ new Map());
@@ -54182,6 +53994,18 @@ Inferred class string: "${iconClasses}."`
54182
53994
  escapePathComponent,
54183
53995
  unescapePathComponent
54184
53996
  });
53997
+ function onTokenChange(cb) {
53998
+ return store.subscribe(getTokenKey(), cb);
53999
+ }
54000
+ function getSessionToken() {
54001
+ return store.getValueSync(getTokenKey());
54002
+ }
54003
+ function setSessionToken(token) {
54004
+ store.setValue(getTokenKey(), token);
54005
+ }
54006
+ function useSessionToken() {
54007
+ return React__namespace.useSyncExternalStore(onTokenChange, getSessionToken);
54008
+ }
54185
54009
  const STORE_EXTRAS_MAP = /* @__PURE__ */ new Map();
54186
54010
  const STORE_VARIABLE_MAP = /* @__PURE__ */ new Map();
54187
54011
  const STORE_SEQUENCE_MAP = /* @__PURE__ */ new Map();
@@ -54495,6 +54319,246 @@ Inferred class string: "${iconClasses}."`
54495
54319
  const deferred = useDeferLoadable(loadable);
54496
54320
  return [deferred, setLoadable];
54497
54321
  }
54322
+ function flexStyles(props, displayCtx2, useDisplayContext) {
54323
+ let flexBasis = props.basis;
54324
+ let flexShrink = props.shrink;
54325
+ let flexGrow = props.grow;
54326
+ if (useDisplayContext) {
54327
+ if (props.width && displayCtx2.direction === "horizontal") {
54328
+ flexBasis != null ? flexBasis : flexBasis = props.width;
54329
+ flexShrink != null ? flexShrink : flexShrink = "0";
54330
+ flexGrow != null ? flexGrow : flexGrow = "0";
54331
+ }
54332
+ if (props.height && displayCtx2.direction === "vertical") {
54333
+ flexBasis != null ? flexBasis : flexBasis = props.height;
54334
+ flexShrink != null ? flexShrink : flexShrink = "0";
54335
+ flexGrow != null ? flexGrow : flexGrow = "0";
54336
+ }
54337
+ }
54338
+ if (props.hug || props.hug !== false && displayCtx2.hug) {
54339
+ flexBasis != null ? flexBasis : flexBasis = "content";
54340
+ flexShrink != null ? flexShrink : flexShrink = "1";
54341
+ flexGrow != null ? flexGrow : flexGrow = "0";
54342
+ }
54343
+ return { flexBasis, flexGrow, flexShrink };
54344
+ }
54345
+ function parseRawCss(rawCss) {
54346
+ const isRawObject = typeof rawCss === "object" && rawCss !== null && rawCss !== void 0;
54347
+ const componentCss = !isRawObject && typeof rawCss === "string" ? rawCss : "";
54348
+ const styles2 = isRawObject ? rawCss : {};
54349
+ return [styles2, componentCss];
54350
+ }
54351
+ function useComponentStyles(props, useDisplayContext = true) {
54352
+ const [rawCssValue] = useVariable(props.raw_css);
54353
+ const [rawStyles, rawCss] = parseRawCss(rawCssValue);
54354
+ const displayCtx$1 = React.useContext(displayCtx);
54355
+ const flexProps = flexStyles(props, displayCtx$1, useDisplayContext);
54356
+ const styles2 = React.useMemo(() => {
54357
+ var _a;
54358
+ const stylesObj = {
54359
+ backgroundColor: props.background,
54360
+ border: props.border,
54361
+ borderRadius: props.border_radius,
54362
+ color: props.color,
54363
+ fontFamily: props.font,
54364
+ fontSize: props.font_size,
54365
+ fontStyle: props.italic ? "italic" : "normal",
54366
+ fontWeight: props.bold ? "bold" : "normal",
54367
+ gap: props.gap,
54368
+ height: props.height,
54369
+ margin: props.margin,
54370
+ maxHeight: props.max_height,
54371
+ maxWidth: props.max_width,
54372
+ minHeight: props.min_height,
54373
+ minWidth: props.min_width,
54374
+ overflow: props.overflow,
54375
+ padding: props.padding,
54376
+ position: props.position,
54377
+ textDecoration: props.underline ? "underline" : "none",
54378
+ width: props.width,
54379
+ ...flexProps,
54380
+ ...rawStyles,
54381
+ ...(_a = props.style) != null ? _a : {}
54382
+ };
54383
+ return Object.fromEntries(Object.entries(stylesObj).filter(([, v2]) => v2 !== null && v2 !== void 0));
54384
+ }, [useDeepCompare(props)]);
54385
+ return [styles2, rawCss];
54386
+ }
54387
+ function useUrlSync(options) {
54388
+ const urlSerializer = React.useCallback((val) => {
54389
+ if (val === void 0 || val === null) {
54390
+ return "";
54391
+ }
54392
+ if (["string", "number", "boolean"].includes(typeof val)) {
54393
+ return String(val);
54394
+ }
54395
+ return JSON.stringify(val);
54396
+ }, []);
54397
+ const urlDeserializer = React.useCallback((val) => {
54398
+ if (val === "") {
54399
+ return void 0;
54400
+ }
54401
+ try {
54402
+ return JSON.parse(val);
54403
+ } catch {
54404
+ return val;
54405
+ }
54406
+ }, []);
54407
+ const listenChangeURL = React.useCallback((handler) => {
54408
+ const unregister = options.history.listen(() => {
54409
+ handler();
54410
+ });
54411
+ return () => unregister();
54412
+ }, []);
54413
+ const memoryOptions = {
54414
+ getURL: () => {
54415
+ return window.location.origin + options.history.location.pathname + options.history.location.search;
54416
+ },
54417
+ pushURL: (url) => {
54418
+ options.history.push(url.replace(window.location.origin, ""));
54419
+ },
54420
+ replaceURL: (url) => {
54421
+ options.history.replace(url.replace(window.location.origin, ""));
54422
+ }
54423
+ };
54424
+ return {
54425
+ browserInterface: {
54426
+ listenChangeURL,
54427
+ ...options.memory_TEST ? memoryOptions : {}
54428
+ },
54429
+ deserialize: urlDeserializer,
54430
+ location: { part: "queryParams" },
54431
+ serialize: urlSerializer
54432
+ };
54433
+ }
54434
+ const Wrapper$2 = styled__default.default.div`
54435
+ display: flex;
54436
+ align-items: center;
54437
+ justify-content: center;
54438
+
54439
+ width: 100%;
54440
+ height: 100%;
54441
+ `;
54442
+ const FlashingDots = styled__default.default.div`
54443
+ position: relative;
54444
+
54445
+ width: 10px;
54446
+ height: 10px;
54447
+
54448
+ color: ${(props) => props.theme.colors.grey4};
54449
+
54450
+ background-color: ${(props) => props.theme.colors.grey4};
54451
+ border-radius: 5px;
54452
+
54453
+ animation: dot-flashing 1s infinite linear alternate;
54454
+ animation-delay: 0.5s;
54455
+
54456
+ &::before,
54457
+ &::after {
54458
+ content: '';
54459
+ position: absolute;
54460
+ top: 0;
54461
+ display: inline-block;
54462
+ }
54463
+
54464
+ &::before {
54465
+ left: -15px;
54466
+
54467
+ width: 10px;
54468
+ height: 10px;
54469
+
54470
+ color: ${(props) => props.theme.colors.grey4};
54471
+
54472
+ background-color: ${(props) => props.theme.colors.grey4};
54473
+ border-radius: 5px;
54474
+
54475
+ animation: dot-flashing 1s infinite alternate;
54476
+ animation-delay: 0s;
54477
+ }
54478
+
54479
+ &::after {
54480
+ left: 15px;
54481
+
54482
+ width: 10px;
54483
+ height: 10px;
54484
+
54485
+ color: ${(props) => props.theme.colors.grey4};
54486
+
54487
+ background-color: ${(props) => props.theme.colors.grey4};
54488
+ border-radius: 5px;
54489
+
54490
+ animation: dot-flashing 1s infinite alternate;
54491
+ animation-delay: 1s;
54492
+ }
54493
+
54494
+ @keyframes dot-flashing {
54495
+ 0% {
54496
+ background-color: ${(props) => props.theme.colors.grey4};
54497
+ }
54498
+
54499
+ 50%,
54500
+ 100% {
54501
+ background-color: ${(props) => props.theme.colors.grey3};
54502
+ }
54503
+ }
54504
+ `;
54505
+ function Dots(props) {
54506
+ return /* @__PURE__ */ React__default.default.createElement(Wrapper$2, { className: props.className, style: props.style }, /* @__PURE__ */ React__default.default.createElement(FlashingDots, { "data-testid": "LOADING" }));
54507
+ }
54508
+ const StyledDots$1 = injectCss(Dots);
54509
+ function DefaultFallback(props) {
54510
+ const [style, css2] = useComponentStyles(props);
54511
+ return /* @__PURE__ */ React__default.default.createElement(StyledDots$1, { $rawCss: css2, style });
54512
+ }
54513
+ const Center = styled__default.default.div`
54514
+ overflow: hidden;
54515
+ display: flex;
54516
+ flex-direction: column;
54517
+ align-items: center;
54518
+ justify-content: center;
54519
+
54520
+ width: 100%;
54521
+ height: 100%;
54522
+
54523
+ background: ${(props) => props.colored ? props.theme.colors.blue1 : ""};
54524
+ `;
54525
+ const CenteredDivWithGap = styled__default.default(Center)`
54526
+ gap: 0.6rem;
54527
+ margin: 10px;
54528
+ text-align: center;
54529
+ `;
54530
+ const errorMessages = {
54531
+ "403": {
54532
+ description: "You are not authorised to access this application. Please contact the application owner to enable access.",
54533
+ styling: "error",
54534
+ title: "We were not able to authenticate you"
54535
+ },
54536
+ default: {
54537
+ description: "Your login session may have expired. Try again.",
54538
+ styling: "primary",
54539
+ title: "We were not able to authenticate you"
54540
+ }
54541
+ };
54542
+ function ErrorPage() {
54543
+ const { search } = useLocation();
54544
+ const query = React.useMemo(() => new URLSearchParams(search), [search]);
54545
+ const code = query.get("code");
54546
+ const errorConfig = code && errorMessages[code] || errorMessages.default;
54547
+ return /* @__PURE__ */ React__default.default.createElement(CenteredDivWithGap, null, /* @__PURE__ */ React__default.default.createElement("h1", null, errorConfig.title), /* @__PURE__ */ React__default.default.createElement("p", null, errorConfig.description), /* @__PURE__ */ React__default.default.createElement(Button$1, { href: "/login", styling: errorConfig.styling }, "Retry"));
54548
+ }
54549
+ function useActionRegistry() {
54550
+ const { actionRegistry: actions } = React.useContext(registriesCtx);
54551
+ const get2 = React.useCallback(
54552
+ (impl) => {
54553
+ if (actions && actions[impl.name]) {
54554
+ return actions[impl.name];
54555
+ }
54556
+ throw new Error(`Attempted to load an action (${impl.name}) that is not in the registry`);
54557
+ },
54558
+ [actions]
54559
+ );
54560
+ return React.useMemo(() => ({ get: get2 }), [get2]);
54561
+ }
54498
54562
  async function invokeAction(input, executionId, annotatedAction, actionCtx) {
54499
54563
  const resolvedKwargs = Object.keys(annotatedAction.dynamic_kwargs).reduce(
54500
54564
  (acc, k2) => {
@@ -55811,7 +55875,8 @@ Inferred class string: "${iconClasses}."`
55811
55875
  `;
55812
55876
  function ErrorDisplay$1(props) {
55813
55877
  var _a, _b, _c, _d, _e2;
55814
- const [styles2, css2] = parseRawCss((_a = props.config) == null ? void 0 : _a.raw_css);
55878
+ const [cssValue] = useVariable((_a = props.config) == null ? void 0 : _a.raw_css);
55879
+ const [styles2, css2] = parseRawCss(cssValue);
55815
55880
  const defaultMessage = props.error instanceof UserError ? props.error.message : "Try again or contact the application owner.";
55816
55881
  return /* @__PURE__ */ React__default.default.createElement(ErrorDisplayWrapper, { $rawCss: css2, style: styles2 }, /* @__PURE__ */ React__default.default.createElement(ContentWrapper, null, /* @__PURE__ */ React__default.default.createElement(ErrorContent, null, /* @__PURE__ */ React__default.default.createElement(ErrorTitle$1, null, /* @__PURE__ */ React__default.default.createElement(IconWrapper, null, /* @__PURE__ */ React__default.default.createElement(ErrorIcon, { "aria-hidden": true, className: "fa-solid fa-circle-xmark fa-lg" })), (_c = (_b = props == null ? void 0 : props.config) == null ? void 0 : _b.title) != null ? _c : "Error"), /* @__PURE__ */ React__default.default.createElement(ErrorText, null, (_e2 = (_d = props == null ? void 0 : props.config) == null ? void 0 : _d.description) != null ? _e2 : defaultMessage))), props.resetErrorBoundary && /* @__PURE__ */ React__default.default.createElement(RetryButton, { onClick: () => props.resetErrorBoundary(props.error), type: "button" }, /* @__PURE__ */ React__default.default.createElement("i", { "aria-hidden": true, className: "fa-solid fa-rotate fa-xl" })));
55817
55882
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dara-core
3
- Version: 1.16.22
3
+ Version: 1.16.23
4
4
  Summary: Dara Framework Core
5
5
  Home-page: https://dara.causalens.com/
6
6
  License: Apache-2.0
@@ -20,10 +20,10 @@ Requires-Dist: async-asgi-testclient (>=1.4.11,<2.0.0)
20
20
  Requires-Dist: certifi (>=2024.7.4)
21
21
  Requires-Dist: click (==8.1.3)
22
22
  Requires-Dist: colorama (>=0.4.6,<0.5.0)
23
- Requires-Dist: create-dara-app (==1.16.22)
23
+ Requires-Dist: create-dara-app (==1.16.23)
24
24
  Requires-Dist: croniter (>=1.0.15,<3.0.0)
25
25
  Requires-Dist: cryptography (>=42.0.4)
26
- Requires-Dist: dara-components (==1.16.22) ; extra == "all"
26
+ Requires-Dist: dara-components (==1.16.23) ; extra == "all"
27
27
  Requires-Dist: exceptiongroup (>=1.1.3,<2.0.0)
28
28
  Requires-Dist: fastapi (>=0.115.0,<0.116.0)
29
29
  Requires-Dist: fastapi_vite_dara (==0.4.0)
@@ -54,7 +54,7 @@ Description-Content-Type: text/markdown
54
54
 
55
55
  # Dara Application Framework
56
56
 
57
- <img src="https://github.com/causalens/dara/blob/v1.16.22/img/dara_light.svg?raw=true">
57
+ <img src="https://github.com/causalens/dara/blob/v1.16.23/img/dara_light.svg?raw=true">
58
58
 
59
59
  ![Master tests](https://github.com/causalens/dara/actions/workflows/tests.yml/badge.svg?branch=master)
60
60
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
@@ -99,7 +99,7 @@ source .venv/bin/activate
99
99
  dara start
100
100
  ```
101
101
 
102
- ![Dara App](https://github.com/causalens/dara/blob/v1.16.22/img/components_gallery.png?raw=true)
102
+ ![Dara App](https://github.com/causalens/dara/blob/v1.16.23/img/components_gallery.png?raw=true)
103
103
 
104
104
  Note: `pip` installation uses [PEP 660](https://peps.python.org/pep-0660/) `pyproject.toml`-based editable installs which require `pip >= 21.3` and `setuptools >= 64.0.0`. You can upgrade both with:
105
105
 
@@ -116,9 +116,9 @@ Explore some of our favorite apps - a great way of getting started and getting t
116
116
 
117
117
  | Dara App | Description |
118
118
  | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
119
- | ![Large Language Model](https://github.com/causalens/dara/blob/v1.16.22/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
120
- | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.16.22/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
121
- | ![Graph Editor](https://github.com/causalens/dara/blob/v1.16.22/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
119
+ | ![Large Language Model](https://github.com/causalens/dara/blob/v1.16.23/img/llm.png?raw=true) | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
120
+ | ![Plot Interactivity](https://github.com/causalens/dara/blob/v1.16.23/img/plot_interactivity.png?raw=true) | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
121
+ | ![Graph Editor](https://github.com/causalens/dara/blob/v1.16.23/img/graph_viewer.png?raw=true) | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
122
122
 
123
123
  Check out our [App Gallery](https://dara.causalens.com/gallery) for more inspiration!
124
124
 
@@ -145,9 +145,9 @@ And the supporting UI packages and tools.
145
145
  - `ui-utils` - miscellaneous utility functions
146
146
  - `ui-widgets` - widget components
147
147
 
148
- More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.16.22/CONTRIBUTING.md) file.
148
+ More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.16.23/CONTRIBUTING.md) file.
149
149
 
150
150
  ## License
151
151
 
152
- Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.16.22/LICENSE).
152
+ Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.16.23/LICENSE).
153
153
 
@@ -12,7 +12,7 @@ dara/core/configuration.py,sha256=bWD9oL_lqCEq88I2Zr39cPt_8jZIwq5vUAyLFrsmVYQ,22
12
12
  dara/core/css.py,sha256=KWCJTPpx4tTezP9VJO3k-RSVhWwomJr-4USoLz9vNAs,1771
13
13
  dara/core/data_utils.py,sha256=5GGz4vk6srLO8HMySiAEk_xZCvmf0SeTTgVi-N4qaKY,12636
14
14
  dara/core/defaults.py,sha256=UkjWwIbo8GLyn8RZRoD3cJe174-3wHZYzvMB0hQCnMg,4150
15
- dara/core/definitions.py,sha256=QouD2P2XInW6bqrhPtrfIyDi8i99Au2PTBdWBtgBVrE,16713
15
+ dara/core/definitions.py,sha256=KmJdLWwurLBRZonPz94N9947cG1jMrs-wzqtof6ubK0,17762
16
16
  dara/core/http.py,sha256=LR1Kr5Hca-Z6klNl-M8R8Q1eOfFh3hLrjVS3kVrRsKA,4658
17
17
  dara/core/interactivity/__init__.py,sha256=zZp4wO6nHZ_-IzDtlv8D5mjlutn4bckqIiSCaPoCYZw,2326
18
18
  dara/core/interactivity/actions.py,sha256=yMw8S11wj4J2HVmDsmedh9D0IZFL9hxw6WGNj7X2f6M,48198
@@ -82,7 +82,7 @@ dara/core/metrics/cache.py,sha256=bGXwjO_rSc-FkS3PnPi1mvIZf1x-hvmG113dAUk1g-Y,26
82
82
  dara/core/metrics/runtime.py,sha256=YP-6Dz0GeI9_Yr7bUk_-OqShyFySGH_AKpDO126l6es,1833
83
83
  dara/core/metrics/utils.py,sha256=aKaa_hskV3M3h4xOGZYvegDLq_OWOEUlslkQKrrPQiI,2281
84
84
  dara/core/persistence.py,sha256=-lnksbGfHwabeRjbJkceoFd0kHfCu4gK2fud8dkeDTg,18538
85
- dara/core/umd/dara.core.umd.js,sha256=ph5XlnK-CaIB7b2iq7NMD3IGaXT7zz0ukn4QLdNjN_8,4723511
85
+ dara/core/umd/dara.core.umd.js,sha256=dHJvK0B3dARTocGdCvCuOVZAx4qHwwviYwX4EaxrwT4,4725934
86
86
  dara/core/umd/style.css,sha256=YQtQ4veiSktnyONl0CU1iU1kKfcQhreH4iASi1MP7Ak,4095007
87
87
  dara/core/visual/__init__.py,sha256=QN0wbG9HPQ_vXh8BO8DnBXeYLIENVTNtRmYzZf1lx7c,577
88
88
  dara/core/visual/components/__init__.py,sha256=eg6M2YcH1o-I2H3IqLaD32ExfZcXhKuH5KTM52Ow6RM,2359
@@ -106,8 +106,8 @@ dara/core/visual/themes/__init__.py,sha256=aM4mgoIYo2neBSw5FRzswsht7PUKjLthiHLmF
106
106
  dara/core/visual/themes/dark.py,sha256=UQGDooOc8ric73eHs9E0ltYP4UCrwqQ3QxqN_fb4PwY,1942
107
107
  dara/core/visual/themes/definitions.py,sha256=nS_gQvOzCt5hTmj74d0_siq_9QWuj6wNuir4VCHy0Dk,2779
108
108
  dara/core/visual/themes/light.py,sha256=-Tviq8oEwGbdFULoDOqPuHO0UpAZGsBy8qFi0kAGolQ,1944
109
- dara_core-1.16.22.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
110
- dara_core-1.16.22.dist-info/METADATA,sha256=OaGKDjB2t-bVSdBdPCJCOz3MbS5V_Cqsb9zazY8dh-I,7507
111
- dara_core-1.16.22.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
112
- dara_core-1.16.22.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
113
- dara_core-1.16.22.dist-info/RECORD,,
109
+ dara_core-1.16.23.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
110
+ dara_core-1.16.23.dist-info/METADATA,sha256=nkpL_PljY5X2YcGsCF4jMTmvKJ8iIcfD2tbrjlsD6Rk,7507
111
+ dara_core-1.16.23.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
112
+ dara_core-1.16.23.dist-info/entry_points.txt,sha256=H__D5sNIGuPIhVam0DChNL-To5k8Y7nY7TAFz9Mz6cc,139
113
+ dara_core-1.16.23.dist-info/RECORD,,