ex4nicegui 0.8.10__py3-none-any.whl → 0.9.1__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.
Files changed (62) hide show
  1. ex4nicegui/__init__.py +3 -2
  2. ex4nicegui/bi/dataSource.py +1 -2
  3. ex4nicegui/bi/elements/ui_aggrid.py +1 -2
  4. ex4nicegui/bi/protocols.py +10 -20
  5. ex4nicegui/layout/rxFlex/index.py +0 -1
  6. ex4nicegui/reactive/EChartsComponent/ECharts.js +1 -1
  7. ex4nicegui/reactive/EChartsComponent/ECharts.py +1 -5
  8. ex4nicegui/reactive/UseDraggable/UseDraggable.py +3 -3
  9. ex4nicegui/reactive/__init__.py +2 -3
  10. ex4nicegui/reactive/_vmodel.py +150 -0
  11. ex4nicegui/reactive/base.py +2 -3
  12. ex4nicegui/reactive/deferredTask.py +2 -5
  13. ex4nicegui/reactive/mermaid/{mermaid.js → ex4ng_mermaid.js} +1 -1
  14. ex4nicegui/reactive/mermaid/mermaid.py +1 -6
  15. ex4nicegui/reactive/mixins/flexLayout.py +4 -8
  16. ex4nicegui/reactive/mixins/value_element.py +1 -2
  17. ex4nicegui/reactive/officials/echarts.py +1 -1
  18. ex4nicegui/reactive/systems/object_system.py +2 -4
  19. ex4nicegui/reactive/usePagination.py +2 -4
  20. ex4nicegui/reactive/vfor.py +1 -0
  21. ex4nicegui/toolbox/core/vue_use.py +1 -1
  22. ex4nicegui/utils/apiEffect.py +1 -2
  23. ex4nicegui/utils/clientScope.py +5 -8
  24. ex4nicegui/utils/effect.py +1 -2
  25. ex4nicegui/utils/page_state.py +70 -0
  26. ex4nicegui/utils/proxy/descriptor.py +0 -1
  27. ex4nicegui/utils/refComputed.py +1 -2
  28. ex4nicegui/utils/refreshable.py +122 -0
  29. ex4nicegui/utils/signals.py +5 -88
  30. {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/METADATA +62 -21
  31. {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/RECORD +54 -80
  32. {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/WHEEL +1 -1
  33. ex4nicegui/gsap/__init__.py +0 -23
  34. ex4nicegui/gsap/gsap.py +0 -145
  35. ex4nicegui/gsap/timeline.js +0 -56
  36. ex4nicegui/gsap/timeline.py +0 -78
  37. ex4nicegui/gsap/wrapGsap.js +0 -48
  38. ex4nicegui/libs/gsap/.DS_Store +0 -0
  39. ex4nicegui/libs/gsap/CSSPlugin.js +0 -1577
  40. ex4nicegui/libs/gsap/CSSRulePlugin.js +0 -134
  41. ex4nicegui/libs/gsap/CustomEase.js +0 -371
  42. ex4nicegui/libs/gsap/Draggable.js +0 -2699
  43. ex4nicegui/libs/gsap/EasePack.js +0 -212
  44. ex4nicegui/libs/gsap/EaselPlugin.js +0 -341
  45. ex4nicegui/libs/gsap/Flip.js +0 -1518
  46. ex4nicegui/libs/gsap/MotionPathPlugin.js +0 -368
  47. ex4nicegui/libs/gsap/Observer.js +0 -686
  48. ex4nicegui/libs/gsap/PixiPlugin.js +0 -461
  49. ex4nicegui/libs/gsap/ScrollToPlugin.js +0 -273
  50. ex4nicegui/libs/gsap/ScrollTrigger.js +0 -2658
  51. ex4nicegui/libs/gsap/TextPlugin.js +0 -166
  52. ex4nicegui/libs/gsap/__init__.py +0 -0
  53. ex4nicegui/libs/gsap/all.js +0 -31
  54. ex4nicegui/libs/gsap/gsap-core.js +0 -4487
  55. ex4nicegui/libs/gsap/gsap.mjs +0 -6
  56. ex4nicegui/libs/gsap/utils/__init__.py +0 -0
  57. ex4nicegui/libs/gsap/utils/matrix.js +0 -420
  58. ex4nicegui/libs/gsap/utils/paths.js +0 -1487
  59. ex4nicegui/libs/gsap/utils/strings.js +0 -107
  60. ex4nicegui/reactive/local_file_picker.py +0 -208
  61. ex4nicegui/reactive/vmodel.py +0 -237
  62. {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,107 +0,0 @@
1
- /*!
2
- * strings: 3.12.5
3
- * https://gsap.com
4
- *
5
- * Copyright 2008-2024, GreenSock. All rights reserved.
6
- * Subject to the terms at https://gsap.com/standard-license or for
7
- * Club GSAP members, the agreement issued with that membership.
8
- * @author: Jack Doyle, jack@greensock.com
9
- */
10
-
11
- /* eslint-disable */
12
- var _trimExp = /(?:^\s+|\s+$)/g;
13
- export var emojiExp = /([\uD800-\uDBFF][\uDC00-\uDFFF](?:[\u200D\uFE0F][\uD800-\uDBFF][\uDC00-\uDFFF]){2,}|\uD83D\uDC69(?:\u200D(?:(?:\uD83D\uDC69\u200D)?\uD83D\uDC67|(?:\uD83D\uDC69\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]\uFE0F|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC6F\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3C-\uDD3E\uDDD6-\uDDDF])\u200D[\u2640\u2642]\uFE0F|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F\u200D[\u2640\u2642]|(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642])\uFE0F|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\uD83D\uDC69\u200D[\u2695\u2696\u2708]|\uD83D\uDC68(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708]))\uFE0F|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83D\uDC69\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|\uD83D\uDC68(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]))|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDD1-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\u200D(?:(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F)/;
14
- export function getText(e) {
15
- var type = e.nodeType,
16
- result = "";
17
-
18
- if (type === 1 || type === 9 || type === 11) {
19
- if (typeof e.textContent === "string") {
20
- return e.textContent;
21
- } else {
22
- for (e = e.firstChild; e; e = e.nextSibling) {
23
- result += getText(e);
24
- }
25
- }
26
- } else if (type === 3 || type === 4) {
27
- return e.nodeValue;
28
- }
29
-
30
- return result;
31
- }
32
- export function splitInnerHTML(element, delimiter, trim, preserveSpaces) {
33
- var node = element.firstChild,
34
- result = [],
35
- s;
36
-
37
- while (node) {
38
- if (node.nodeType === 3) {
39
- s = (node.nodeValue + "").replace(/^\n+/g, "");
40
-
41
- if (!preserveSpaces) {
42
- s = s.replace(/\s+/g, " ");
43
- }
44
-
45
- result.push.apply(result, emojiSafeSplit(s, delimiter, trim, preserveSpaces));
46
- } else if ((node.nodeName + "").toLowerCase() === "br") {
47
- result[result.length - 1] += "<br>";
48
- } else {
49
- result.push(node.outerHTML);
50
- }
51
-
52
- node = node.nextSibling;
53
- }
54
-
55
- s = result.length;
56
-
57
- while (s--) {
58
- result[s] === "&" && result.splice(s, 1, "&amp;");
59
- }
60
-
61
- return result;
62
- }
63
- /*
64
- //smaller kb version that only handles the simpler emoji's, which is often perfectly adequate.
65
-
66
- let _emoji = "[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D]|[\uD800-\uDBFF][\uDC00-\uDFFF]",
67
- _emojiExp = new RegExp(_emoji),
68
- _emojiAndCharsExp = new RegExp(_emoji + "|.", "g"),
69
- _emojiSafeSplit = (text, delimiter, trim) => {
70
- if (trim) {
71
- text = text.replace(_trimExp, "");
72
- }
73
- return ((delimiter === "" || !delimiter) && _emojiExp.test(text)) ? text.match(_emojiAndCharsExp) : text.split(delimiter || "");
74
- };
75
- */
76
-
77
- export function emojiSafeSplit(text, delimiter, trim, preserveSpaces) {
78
- text += ""; // make sure it's cast as a string. Someone may pass in a number.
79
-
80
- trim && (text = text.trim ? text.trim() : text.replace(_trimExp, "")); // IE9 and earlier compatibility
81
-
82
- if (delimiter && delimiter !== "") {
83
- return text.replace(/>/g, "&gt;").replace(/</g, "&lt;").split(delimiter);
84
- }
85
-
86
- var result = [],
87
- l = text.length,
88
- i = 0,
89
- j,
90
- character;
91
-
92
- for (; i < l; i++) {
93
- character = text.charAt(i);
94
-
95
- if (character.charCodeAt(0) >= 0xD800 && character.charCodeAt(0) <= 0xDBFF || text.charCodeAt(i + 1) >= 0xFE00 && text.charCodeAt(i + 1) <= 0xFE0F) {
96
- //special emoji characters use 2 or 4 unicode characters that we must keep together.
97
- j = ((text.substr(i, 12).split(emojiExp) || [])[1] || "").length || 2;
98
- character = text.substr(i, j);
99
- result.emoji = 1;
100
- i += j - 1;
101
- }
102
-
103
- result.push(character === ">" ? "&gt;" : character === "<" ? "&lt;" : preserveSpaces && character === " " && (text.charAt(i - 1) === " " || text.charAt(i + 1) === " ") ? "&nbsp;" : character);
104
- }
105
-
106
- return result;
107
- }
@@ -1,208 +0,0 @@
1
- from typing import Callable, Optional, List, Union
2
- from typing_extensions import Literal
3
- from nicegui import ui, Tailwind
4
- from pathlib import Path
5
-
6
- from ex4nicegui.utils.signals import (
7
- Ref,
8
- effect_refreshable,
9
- effect,
10
- ref_computed as computed,
11
- to_ref,
12
- )
13
-
14
-
15
- SelectMode = Literal["dir", "file"]
16
-
17
-
18
- class LocalFilePickerResult:
19
- def __init__(self, ref: Ref[str], open_fn: Callable[..., None]) -> None:
20
- self.__open_fn = open_fn
21
- self._ref = ref
22
-
23
- def open(self):
24
- self.__open_fn()
25
-
26
- def bind_ref(self, ref: Ref[str]):
27
- @effect
28
- def _():
29
- ref.value = self._ref.value
30
-
31
- return self
32
-
33
-
34
- def local_file_picker(
35
- title: Optional[str] = None,
36
- dir: Optional[Union[str, Path]] = None,
37
- mode: SelectMode = "file",
38
- ext: Optional[List[str]] = None,
39
- ):
40
- """本地文件目录选择框
41
-
42
- Args:
43
- title (Optional[str], optional): 标题. Defaults to None.
44
- dir (Optional[str], optional): 起始目录,默认为当前目录. Defaults to None.
45
- mode (SelectMode, optional): 选择文件或选择目录,'file' | 'dir'. Defaults to "file".
46
- ext (Optional[List[str]], optional): 当 `mode` 为 'file' 时,保留指定的文件后缀.例如: ```ext=['.xlsx','.csv']```. Defaults to None.
47
-
48
- Returns:
49
- _type_: open,result
50
- open:打开选择框函数
51
- result: 获取结果的信号函数。
52
-
53
- 例子:
54
- ```python
55
-
56
- fp = local_file_picker(dir=r"D://dataset", ext=[".xlsx"])
57
- fp.open()
58
-
59
- # 获取结果
60
- fp.value
61
- ```
62
- """
63
- # data define
64
- title = title or "选择文件" if mode == "file" else "选择文件夹"
65
- dir_path = Path(dir).absolute() if dir else Path("./").absolute()
66
-
67
- # 当前所在目录
68
- cur_dir = to_ref(dir_path)
69
- cur_name = computed(lambda: str(cur_dir.value.absolute()))
70
-
71
- # 选中的路径
72
- selected = to_ref("")
73
-
74
- # 返回外部的结果路径
75
- result = to_ref("")
76
-
77
- no_ex_filter = ext is None
78
- ext_set = set(ext or [])
79
-
80
- def filter_ex(p: Path):
81
- if mode == "dir" or p.is_dir() or no_ex_filter:
82
- return True
83
-
84
- return p.suffix in ext_set
85
-
86
- # 当前目录下的文件(或目录)的列表
87
- @computed
88
- def paths():
89
- all_paths = sorted(cur_dir.value.glob("*"), key=lambda x: not x.is_dir())
90
-
91
- all_paths = (p for p in all_paths if mode == "file" or p.is_dir())
92
- all_paths = [p for p in all_paths if filter_ex(p)]
93
-
94
- return all_paths
95
-
96
- # ui define
97
- row_text_style = Tailwind().align_items("center").justify_content("center")
98
-
99
- dia = ui.dialog().props("persistent")
100
-
101
- with dia, ui.card().style("max-width:fit-content"):
102
- with ui.row().classes("w-full"):
103
- ui.label(title).classes("mr-auto")
104
-
105
- ui.icon("close", size="xs").classes("cursor-pointer").on(
106
- "click", handler=lambda: dia.close()
107
- )
108
-
109
- with ui.row().classes("w-full") as row:
110
- row.tailwind(row_text_style)
111
-
112
- # ui_cur_dir = ui.label()
113
- # bind_from(ui_cur_dir, cur_name)
114
-
115
- def onenter():
116
- cur_dir.value = Path(ui_cur_dir.value)
117
-
118
- ui_cur_dir = ui.input(
119
- "当前路径", validation={"无效路径": lambda value: Path(value).exists()}
120
- ).on("keydown.enter", handler=onenter)
121
- ui_cur_dir.classes("mr-auto grow")
122
-
123
- @effect
124
- def _():
125
- ui_cur_dir.value = cur_name()
126
-
127
- @effect_refreshable
128
- def pre_btn():
129
- dir = cur_dir.value
130
- if dir.is_dir() and dir.parent.is_dir():
131
-
132
- def onclick():
133
- cur_dir.value = dir.parent
134
-
135
- ui.button("上一级", on_click=onclick)
136
-
137
- # 文件或目录的表格
138
- @effect_refreshable
139
- def paths_table():
140
- rowData = [
141
- {"名称": p.name, "类型": "文件夹" if p.is_dir() else "文件"}
142
- for p in paths()
143
- ]
144
-
145
- grid = ui.aggrid(
146
- {
147
- "defaultColDef": {
148
- "resizable": True,
149
- },
150
- "columnDefs": [
151
- {
152
- "field": "名称",
153
- },
154
- {
155
- "field": "类型",
156
- },
157
- # {'field':'修改日期',},
158
- # {'field':'大小',},
159
- ],
160
- "rowData": rowData,
161
- }
162
- )
163
-
164
- grid.style("width:50vw")
165
- # grid.tailwind("w-96")
166
-
167
- def dblClicked(e):
168
- path = cur_dir.value / Path(e.args["data"]["名称"])
169
-
170
- if path.is_dir():
171
- cur_dir.value = path
172
- return
173
-
174
- if mode == "file" and path.is_file():
175
- result.value = str(path.absolute())
176
- dia.close()
177
-
178
- def clicked(e):
179
- path = cur_dir.value / Path(e.args["data"]["名称"])
180
-
181
- if mode == "file" and path.is_dir():
182
- return
183
- selected.value = str(path)
184
-
185
- grid.on("cellDoubleClicked", handler=dblClicked)
186
- grid.on("cellClicked", handler=clicked)
187
-
188
- # 页脚部分
189
- with ui.row():
190
- ui_selected_label = ui.label("当前选择:")
191
-
192
- @effect
193
- def _():
194
- ui_selected_label.text = f"当前选择: {Path(selected.value).name}"
195
-
196
- def onclick_ok():
197
- dia.close()
198
- result.value = selected.value
199
-
200
- ok_btn = ui.button("ok", on_click=onclick_ok)
201
-
202
- @effect
203
- def _():
204
- ok_btn.set_enabled(len(selected.value) > 0)
205
-
206
- file_picker_result = LocalFilePickerResult(result, dia.open)
207
-
208
- return file_picker_result
@@ -1,237 +0,0 @@
1
- from __future__ import annotations
2
- import inspect
3
- from io import BytesIO
4
- from ex4nicegui.utils.signals import (
5
- RefWrapper,
6
- TRef,
7
- to_raw,
8
- is_setter_ref,
9
- to_ref_wrapper,
10
- to_value,
11
- is_reactive,
12
- )
13
- from typing import (
14
- Any,
15
- Callable,
16
- TypeVar,
17
- Union,
18
- cast,
19
- Tuple,
20
- NamedTuple,
21
- )
22
-
23
- from types import FrameType
24
- import tokenize
25
- import executing
26
- import ast
27
- import warnings
28
- from ex4nicegui.reactive.systems.object_system import get_attribute, set_attribute
29
- from ex4nicegui.utils.types import _TMaybeRef as TMaybeRef, Ref
30
-
31
- _T = TypeVar("_T")
32
-
33
-
34
- def get_caller() -> FrameType:
35
- return inspect.currentframe().f_back.f_back # type: ignore
36
-
37
-
38
- def get_args_code(caller: FrameType) -> str:
39
- node = executing.Source.executing(caller).node
40
-
41
- assert isinstance(node, ast.Call)
42
-
43
- source = inspect.getsource(inspect.getmodule(caller)) # type: ignore
44
- key_code = ast.get_source_segment(source, node.args[0])
45
- return key_code # type: ignore
46
-
47
-
48
- class CodeInfo(NamedTuple):
49
- model: str
50
- is_ref: bool
51
- keys: Tuple[Union[str, int], ...] = tuple() # type: ignore
52
-
53
-
54
- def normalize(token: tokenize.TokenInfo):
55
- if token.type == tokenize.NUMBER:
56
- return int(token.string)
57
-
58
- if token.type == tokenize.STRING:
59
- return token.string[1:-1]
60
-
61
- return token.string
62
-
63
-
64
- def parse_code(code: str) -> CodeInfo:
65
- tokens = [
66
- t
67
- for t in tokenize.tokenize(BytesIO(code.encode("utf8")).readline)
68
- if t.type in (tokenize.NAME, tokenize.NUMBER, tokenize.OP, tokenize.STRING)
69
- ]
70
-
71
- model = tokens[0].string
72
- is_ref = (
73
- len(tokens) >= 3
74
- and tokens[1].type == tokenize.OP
75
- and tokens[1].string == "."
76
- and tokens[2].string == "value"
77
- )
78
-
79
- keys_search_start = 3 if is_ref else 1
80
-
81
- keys = tuple(
82
- normalize(token)
83
- for token in tokens[keys_search_start:]
84
- if token.type != tokenize.OP
85
- )
86
-
87
- return CodeInfo(model, is_ref, keys)
88
-
89
-
90
- def create_writeable_wrapper(expr, ref_data, attrs: Tuple[Union[str, int], ...]):
91
- if not attrs:
92
-
93
- def maybe_ref_getter():
94
- return to_value(expr)
95
-
96
- def reactive_getter():
97
- return to_raw(expr)
98
-
99
- def setter(value):
100
- pass
101
-
102
- wrapper = to_ref_wrapper(
103
- reactive_getter if is_reactive(expr) else maybe_ref_getter,
104
- setter,
105
- )
106
- wrapper._is_readonly = False
107
- return wrapper
108
-
109
- def getter():
110
- obj = get_attribute(to_value(ref_data), attrs[0])
111
- for attr in attrs[1:]:
112
- obj = get_attribute(obj, attr)
113
-
114
- return obj
115
-
116
- def setter(value):
117
- obj = to_value(ref_data)
118
-
119
- for attr in attrs[:-1]:
120
- obj = get_attribute(obj, attr)
121
-
122
- set_attribute(obj, attrs[-1], value)
123
-
124
- wrapper = to_ref_wrapper(
125
- getter,
126
- setter,
127
- )
128
- wrapper._is_readonly = False
129
- return wrapper
130
-
131
-
132
- def vmodel(expr: Any, *attrs: Union[str, int]) -> TRef[Any]:
133
- """Create a two-way binding on a form input element or a component.
134
-
135
- @see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#vmodel
136
- @中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#vmodel
137
-
138
- Args:
139
- expr (Any): _description_
140
-
141
- ## Examples
142
-
143
- .. code-block:: python
144
- from ex4nicegui.reactive import rxui
145
- from ex4nicegui import deep_ref
146
-
147
- data = deep_ref({"a": 1, "b": [1, 2, 3, 4]})
148
-
149
- rxui.label(lambda: f"{data.value=!s}")
150
-
151
- # No binding effect
152
- rxui.input(value=data.value["a"])
153
-
154
- # readonly binding
155
- rxui.input(value=lambda: data.value["a"])
156
-
157
- # two-way binding
158
- rxui.input(value=rxui.vmodel(data.value,'a'))
159
-
160
-
161
- """
162
-
163
- assert not isinstance(expr, Callable), "argument expr cannot be a function"
164
-
165
- if isinstance(expr, RefWrapper):
166
- expr._is_readonly = False
167
-
168
- if is_setter_ref(expr):
169
- if attrs:
170
- wrapper = create_writeable_wrapper(expr, expr, attrs)
171
-
172
- return cast(
173
- TRef,
174
- wrapper,
175
- )
176
-
177
- return cast(
178
- TRef,
179
- expr,
180
- )
181
-
182
- caller = get_caller()
183
- code = get_args_code(caller)
184
-
185
- info = parse_code(code)
186
- ref_data = caller.f_locals.get(info.model) or caller.f_globals.get(info.model)
187
- assert ref_data is not None, f"{info.model} not found"
188
- all_attrs = (*info.keys, *attrs)
189
-
190
- if not all_attrs:
191
- warn_mes = ""
192
- if is_reactive(expr) or is_setter_ref(expr):
193
- warn_mes = rf"""Expression missing the key,result is read-only binding.Maybe you meant `{code}['key']`"""
194
- elif not info.is_ref:
195
- warn_mes = """Maybe you don't need to use vmodel"""
196
- else:
197
- warn_mes = rf"""No binding.Maybe you meant `{info.model}`"""
198
-
199
- warnings.warn(
200
- warn_mes,
201
- stacklevel=2,
202
- )
203
-
204
- wrapper = create_writeable_wrapper(expr, ref_data, all_attrs)
205
-
206
- return cast(
207
- TRef,
208
- wrapper,
209
- )
210
-
211
-
212
- def vmodel_with_index(ref: Ref, index: TMaybeRef[int], *keys: Union[str, int]) -> Ref:
213
- proxy = ref.value
214
-
215
- def getter():
216
- item = proxy[to_value(index)]
217
- result = item
218
-
219
- for k in keys:
220
- result = get_attribute(result, k)
221
- return result
222
-
223
- def setter(value):
224
- item = proxy[to_value(index)]
225
-
226
- if len(keys) == 1:
227
- set_attribute(item, keys[0], value)
228
- return
229
-
230
- obj = get_attribute(item, keys[0])
231
-
232
- for k in keys[1:-1]:
233
- set_attribute(obj, k, get_attribute(obj, k))
234
-
235
- set_attribute(obj, keys[-1], value)
236
-
237
- return RefWrapper(getter, setter) # type: ignore