instaui 0.1.5__py3-none-any.whl → 0.1.7__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 (132) hide show
  1. instaui/arco/__init__.py +191 -0
  2. instaui/arco/_settings.py +25 -0
  3. instaui/arco/_use_tools/locale.py +50 -0
  4. instaui/arco/component_types.py +1019 -0
  5. instaui/arco/components/_utils.py +22 -0
  6. instaui/arco/components/affix.py +29 -0
  7. instaui/arco/components/alert.py +42 -0
  8. instaui/arco/components/anchor.py +42 -0
  9. instaui/arco/components/auto_complete.py +96 -0
  10. instaui/arco/components/avatar.py +55 -0
  11. instaui/arco/components/back_top.py +14 -0
  12. instaui/arco/components/badge.py +14 -0
  13. instaui/arco/components/breadcrumb.py +14 -0
  14. instaui/arco/components/button.py +43 -0
  15. instaui/arco/components/calendar.py +47 -0
  16. instaui/arco/components/card.py +14 -0
  17. instaui/arco/components/carousel.py +33 -0
  18. instaui/arco/components/cascader.py +111 -0
  19. instaui/arco/components/checkbox.py +32 -0
  20. instaui/arco/components/collapse.py +31 -0
  21. instaui/arco/components/color_picker.py +45 -0
  22. instaui/arco/components/comment.py +14 -0
  23. instaui/arco/components/config_provider.py +13 -0
  24. instaui/arco/components/date_picker.py +111 -0
  25. instaui/arco/components/descriptions.py +14 -0
  26. instaui/arco/components/divider.py +13 -0
  27. instaui/arco/components/drawer.py +98 -0
  28. instaui/arco/components/dropdown.py +45 -0
  29. instaui/arco/components/empty.py +14 -0
  30. instaui/arco/components/form.py +55 -0
  31. instaui/arco/components/icon.py +17 -0
  32. instaui/arco/components/image.py +33 -0
  33. instaui/arco/components/input.py +102 -0
  34. instaui/arco/components/input_number.py +97 -0
  35. instaui/arco/components/input_password.py +38 -0
  36. instaui/arco/components/input_search.py +37 -0
  37. instaui/arco/components/input_tag.py +110 -0
  38. instaui/arco/components/layout.py +13 -0
  39. instaui/arco/components/layout_content.py +6 -0
  40. instaui/arco/components/layout_footer.py +6 -0
  41. instaui/arco/components/layout_header.py +6 -0
  42. instaui/arco/components/layout_sider.py +53 -0
  43. instaui/arco/components/link.py +36 -0
  44. instaui/arco/components/list.py +68 -0
  45. instaui/arco/components/mention.py +97 -0
  46. instaui/arco/components/menu.py +88 -0
  47. instaui/arco/components/modal.py +97 -0
  48. instaui/arco/components/overflow_list.py +29 -0
  49. instaui/arco/components/page_header.py +29 -0
  50. instaui/arco/components/pagination.py +45 -0
  51. instaui/arco/components/pop_confirm.py +58 -0
  52. instaui/arco/components/popover.py +32 -0
  53. instaui/arco/components/progress.py +14 -0
  54. instaui/arco/components/radio.py +40 -0
  55. instaui/arco/components/radio_group.py +42 -0
  56. instaui/arco/components/rate.py +45 -0
  57. instaui/arco/components/resize_box.py +62 -0
  58. instaui/arco/components/result.py +14 -0
  59. instaui/arco/components/select.py +179 -0
  60. instaui/arco/components/skeleton.py +14 -0
  61. instaui/arco/components/slider.py +38 -0
  62. instaui/arco/components/space.py +14 -0
  63. instaui/arco/components/spin.py +14 -0
  64. instaui/arco/components/split.py +76 -0
  65. instaui/arco/components/statistic.py +14 -0
  66. instaui/arco/components/steps.py +32 -0
  67. instaui/arco/components/switch.py +57 -0
  68. instaui/arco/components/tab_pane.py +12 -0
  69. instaui/arco/components/table.py +276 -0
  70. instaui/arco/components/tabs.py +101 -0
  71. instaui/arco/components/tag.py +42 -0
  72. instaui/arco/components/textarea.py +84 -0
  73. instaui/arco/components/time_picker.py +76 -0
  74. instaui/arco/components/timeline.py +14 -0
  75. instaui/arco/components/tooltip.py +29 -0
  76. instaui/arco/components/transfer.py +58 -0
  77. instaui/arco/components/tree.py +120 -0
  78. instaui/arco/components/tree_select.py +86 -0
  79. instaui/arco/components/trigger.py +58 -0
  80. instaui/arco/components/typography.py +142 -0
  81. instaui/arco/components/upload.py +71 -0
  82. instaui/arco/components/verification_code.py +58 -0
  83. instaui/arco/components/watermark.py +14 -0
  84. instaui/arco/locales/__init__.py +4 -0
  85. instaui/arco/locales/_index.py +31 -0
  86. instaui/arco/locales/en_us.py +227 -0
  87. instaui/arco/locales/zh_cn.py +224 -0
  88. instaui/arco/setup.py +36 -0
  89. instaui/arco/static/instaui-arco.css +1 -0
  90. instaui/arco/static/instaui-arco.js +55771 -0
  91. instaui/arco/types.py +24 -0
  92. instaui/components/column.py +10 -2
  93. instaui/components/element.py +0 -2
  94. instaui/components/grid.py +81 -0
  95. instaui/components/markdown/static/github-markdown.css +1 -1
  96. instaui/components/row.py +8 -7
  97. instaui/components/shiki_code/static/shiki-style.css +179 -175
  98. instaui/experimental/link_sql/__init__.py +3 -0
  99. instaui/experimental/link_sql/_base.py +23 -0
  100. instaui/experimental/link_sql/_duckdb.py +221 -0
  101. instaui/experimental/link_sql/_types.py +15 -0
  102. instaui/experimental/link_sql/data_source.js +50 -0
  103. instaui/fastapi_server/debug_mode_router.py +1 -1
  104. instaui/html_tools.py +2 -3
  105. instaui/runtime/scope.py +28 -7
  106. instaui/static/insta-ui.css +1 -1
  107. instaui/static/insta-ui.esm-browser.prod.js +3663 -3719
  108. instaui/static/insta-ui.js.map +1 -1
  109. instaui/static/templates/debug/sse.html +1 -1
  110. instaui/tailwind/_index.py +2 -2
  111. instaui/ui_functions/ui_page.py +1 -1
  112. instaui/vars/data.py +7 -7
  113. instaui/vars/element_ref.py +2 -4
  114. instaui/vars/js_computed.py +6 -8
  115. instaui/vars/ref.py +6 -6
  116. instaui/vars/vue_computed.py +6 -7
  117. instaui/vars/web_computed.py +2 -3
  118. instaui/watch/vue_watch.py +23 -7
  119. instaui/zero/scope.py +3 -20
  120. {instaui-0.1.5.dist-info → instaui-0.1.7.dist-info}/METADATA +8 -5
  121. {instaui-0.1.5.dist-info → instaui-0.1.7.dist-info}/RECORD +123 -36
  122. instaui/daisyui/__init__.py +0 -26
  123. instaui/daisyui/_index.py +0 -20
  124. instaui/daisyui/button.py +0 -38
  125. instaui/daisyui/checkbox.py +0 -17
  126. instaui/daisyui/static/daisyui.css +0 -1
  127. instaui/daisyui/static/themes.css +0 -1
  128. instaui/daisyui/table.py +0 -35
  129. instaui/ui/__build_init.py +0 -73
  130. instaui/vars/_utils.py +0 -12
  131. {instaui-0.1.5.dist-info → instaui-0.1.7.dist-info}/LICENSE +0 -0
  132. {instaui-0.1.5.dist-info → instaui-0.1.7.dist-info}/WHEEL +0 -0
@@ -1,175 +1,179 @@
1
- :root {
2
- --shiki-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;
3
- --shiki-code-line-height: 1.5;
4
- --shiki-code-font-size: 0.875em;
5
- --shiki-code-block-color: #67676c;
6
- --shiki-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");
7
- --shiki-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E");
8
- --shiki-code-copy-code-border-color: #e2e2e3;
9
- --shiki-code-copy-code-bg: #f6f6f7;
10
- --shiki-code-copy-code-hover-border-color: #e2e2e3;
11
- --shiki-code-copy-code-hover-bg: #ffffff;
12
- --shiki-code-copy-code-active-text: #67676c;
13
- --shiki-code-copy-copied-text-content: "Copied";
14
- --shiki-code-lang-color: #929295;
15
- }
16
- @media (min-width: 640px) {
17
- .shiki-code[class*=language-] {
18
- border-radius: 8px;
19
- margin: 15px 0;
20
- }
21
- }
22
- .shiki-code[class*=language-] {
23
- position: relative;
24
- margin: 16px 0;
25
- background-color: #f9f9f9;
26
- overflow-x: auto;
27
- transition: background-color 0.5s;
28
- /* line numbers */
29
- }
30
- .shiki-code[class*=language-] pre,
31
- .shiki-code[class*=language-] code {
32
- font-family: var(--shiki-font-family-mono);
33
- }
34
- .shiki-code[class*=language-] pre {
35
- position: relative;
36
- z-index: 1;
37
- margin: 0;
38
- padding: 20px 0;
39
- background: transparent;
40
- overflow-x: auto;
41
- }
42
- .shiki-code[class*=language-] code {
43
- display: block;
44
- padding: 0 24px 0 0;
45
- width: fit-content;
46
- min-width: 100%;
47
- line-height: var(--shiki-code-line-height);
48
- font-size: var(--shiki-code-font-size);
49
- color: var(--shiki-code-block-color);
50
- transition: color 0.5s;
51
- }
52
- .shiki-code[class*=language-] code > .line:before {
53
- content: ' ';
54
- padding: 0 5px;
55
- }
56
- .shiki-code[class*=language-] > button.copy {
57
- direction: ltr;
58
- position: absolute;
59
- top: 12px;
60
- right: 12px;
61
- z-index: 3;
62
- border: 1px solid var(--shiki-code-copy-code-border-color);
63
- border-radius: 4px;
64
- width: 40px;
65
- height: 40px;
66
- background-color: var(--shiki-code-copy-code-bg);
67
- opacity: 0;
68
- cursor: pointer;
69
- background-image: var(--shiki-icon-copy);
70
- background-position: 50%;
71
- background-size: 20px;
72
- background-repeat: no-repeat;
73
- transition: border-color 0.25s, background-color 0.25s, opacity 0.25s;
74
- }
75
- .shiki-code[class*=language-]:hover > button.copy,
76
- .shiki-code[class*=language-] > button.copy:focus {
77
- opacity: 1;
78
- }
79
- .shiki-code[class*=language-] > button.copy:hover,
80
- .shiki-code[class*=language-] > button.copy.copied {
81
- border-color: var(--shiki-code-copy-code-hover-border-color);
82
- background-color: var(--shiki-code-copy-code-hover-bg);
83
- }
84
- .shiki-code[class*=language-] > button.copy.copied,
85
- .shiki-code[class*=language-] > button.copy:hover.copied {
86
- border-radius: 0 4px 4px 0;
87
- background-color: var(--shiki-code-copy-code-hover-bg);
88
- background-image: var(--shiki-icon-copied);
89
- }
90
- .shiki-code[class*=language-] > button.copy.copied:before,
91
- .shiki-code[class*=language-] > button.copy:hover.copied:before {
92
- position: relative;
93
- top: -1px;
94
- display: flex;
95
- justify-content: center;
96
- align-items: center;
97
- border: 1px solid var(--shiki-code-copy-code-hover-border-color);
98
- border-right: 0;
99
- border-radius: 4px 0 0 4px;
100
- padding: 0 10px;
101
- width: fit-content;
102
- height: 40px;
103
- text-align: center;
104
- font-size: 12px;
105
- font-weight: 500;
106
- color: var(--shiki-code-copy-code-active-text);
107
- background-color: var(--shiki-code-copy-code-hover-bg);
108
- white-space: nowrap;
109
- content: var(--shiki-code-copy-copied-text-content);
110
- transform: translate(calc(-100% - 1px));
111
- }
112
- .shiki-code[class*=language-] > span.lang {
113
- position: absolute;
114
- top: 2px;
115
- right: 8px;
116
- z-index: 2;
117
- font-size: 12px;
118
- font-weight: 500;
119
- -webkit-user-select: none;
120
- user-select: none;
121
- color: var(--shiki-code-lang-color);
122
- transition: color 0.4s, opacity 0.4s;
123
- }
124
- .shiki-code[class*=language-]:hover > button.copy + span.lang,
125
- .shiki-code[class*=language-] > button.copy:focus + span.lang {
126
- opacity: 0;
127
- }
128
- .shiki-code[class*=language-].theme-dark {
129
- --shiki-code-line-diff-add-color: #3dd68c;
130
- --shiki-code-line-diff-add-symbol-color: #3dd68c;
131
- --shiki-code-line-diff-remove-color: hsla(349.72, 89.16%, 60.2%, 0.16);
132
- --shiki-code-line-diff-remove-symbol-color: hsl(357.62, 39.92%, 50.39%);
133
- --shiki-code-line-line-number-color: hsla(198.18, 13.36%, 80%, 0.7);
134
- }
135
- .shiki-code[class*=language-] pre.shiki .diff {
136
- all: unset;
137
- }
138
- .shiki-code[class*=language-] pre.shiki code .diff.remove {
139
- background-color: var(--shiki-code-line-diff-remove-color, rgba(244, 63, 94, 0.14));
140
- opacity: 0.7;
141
- }
142
- .shiki-code[class*=language-] pre.shiki code .diff.add {
143
- background-color: rgba(16, 185, 129, 0.14);
144
- }
145
- .shiki-code[class*=language-] pre.shiki code .diff.add:before {
146
- content: "+";
147
- color: var(--shiki-code-line-diff-add-symbol-color, #18794e);
148
- }
149
- .shiki-code[class*=language-] pre.shiki code .diff.remove:before {
150
- content: "-";
151
- color: var(--shiki-code-line-diff-remove-symbol-color, hsl(357.62, 39.92%, 50.39%));
152
- }
153
- .shiki-code[class*=language-] pre.shiki code .diff:before {
154
- padding: 0 10px;
155
- }
156
- .shiki-code[class*=language-] pre.shiki code .diff {
157
- box-sizing: border-box;
158
- transition: background-color 0.5s;
159
- margin: 0 -24px;
160
- padding: 0 24px;
161
- width: calc(100% + 48px);
162
- display: inline-block;
163
- }
164
- .shiki-code[class*=language-].line-numbers code {
165
- counter-reset: step;
166
- counter-increment: step 0;
167
- }
168
- .shiki-code[class*=language-].line-numbers code .line::before {
169
- padding: 0 10px;
170
- content: counter(step);
171
- counter-increment: step;
172
- display: inline-block;
173
- text-align: right;
174
- color: var(--shiki-code-line-line-number-color, hsla(198.18, 13.36%, 51.57%, 0.7));
175
- }
1
+ :root {
2
+ --shiki-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;
3
+ --shiki-code-line-height: 1.5;
4
+ --shiki-code-font-size: 0.875em;
5
+ --shiki-code-block-color: #67676c;
6
+ --shiki-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");
7
+ --shiki-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E");
8
+ --shiki-code-copy-code-border-color: #e2e2e3;
9
+ --shiki-code-copy-code-bg: #f6f6f7;
10
+ --shiki-code-copy-code-hover-border-color: #e2e2e3;
11
+ --shiki-code-copy-code-hover-bg: #ffffff;
12
+ --shiki-code-copy-code-active-text: #67676c;
13
+ --shiki-code-copy-copied-text-content: "Copied";
14
+ --shiki-code-lang-color: #929295;
15
+ }
16
+ @media (min-width: 640px) {
17
+ .shiki-code[class*=language-] {
18
+ border-radius: 8px;
19
+ margin: 15px 0;
20
+ }
21
+ }
22
+ .shiki-code[class*=language-] {
23
+ position: relative;
24
+ margin: 16px 0;
25
+ background-color: #f9f9f9;
26
+ overflow-x: auto;
27
+ transition: background-color 0.5s;
28
+ /* line numbers */
29
+ }
30
+ .shiki-code[class*=language-] pre,
31
+ .shiki-code[class*=language-] code {
32
+ font-family: var(--shiki-font-family-mono);
33
+ }
34
+ .shiki-code[class*=language-] pre {
35
+ position: relative;
36
+ z-index: 1;
37
+ margin: 0;
38
+ padding: 20px 0;
39
+ background: transparent;
40
+ overflow-x: auto;
41
+ }
42
+ .shiki-code[class*=language-] code {
43
+ display: block;
44
+ padding: 0 24px 0 0;
45
+ width: fit-content;
46
+ min-width: 100%;
47
+ line-height: var(--shiki-code-line-height);
48
+ font-size: var(--shiki-code-font-size);
49
+ color: var(--shiki-code-block-color);
50
+ transition: color 0.5s;
51
+ }
52
+ .shiki-code[class*=language-] code > .line:before {
53
+ content: ' ';
54
+ padding: 0 5px;
55
+ }
56
+ .shiki-code[class*=language-] > button.copy {
57
+ direction: ltr;
58
+ position: absolute;
59
+ top: 12px;
60
+ right: 12px;
61
+ z-index: 3;
62
+ border: 1px solid var(--shiki-code-copy-code-border-color);
63
+ border-radius: 4px;
64
+ width: 40px;
65
+ height: 40px;
66
+ background-color: var(--shiki-code-copy-code-bg);
67
+ opacity: 0;
68
+ cursor: pointer;
69
+ background-image: var(--shiki-icon-copy);
70
+ background-position: 50%;
71
+ background-size: 20px;
72
+ background-repeat: no-repeat;
73
+ transition: border-color 0.25s, background-color 0.25s, opacity 0.25s;
74
+ }
75
+ .shiki-code[class*=language-]:hover > button.copy,
76
+ .shiki-code[class*=language-] > button.copy:focus {
77
+ opacity: 1;
78
+ }
79
+ .shiki-code[class*=language-] > button.copy:hover,
80
+ .shiki-code[class*=language-] > button.copy.copied {
81
+ border-color: var(--shiki-code-copy-code-hover-border-color);
82
+ background-color: var(--shiki-code-copy-code-hover-bg);
83
+ }
84
+ .shiki-code[class*=language-] > button.copy.copied,
85
+ .shiki-code[class*=language-] > button.copy:hover.copied {
86
+ border-radius: 0 4px 4px 0;
87
+ background-color: var(--shiki-code-copy-code-hover-bg);
88
+ background-image: var(--shiki-icon-copied);
89
+ }
90
+ .shiki-code[class*=language-] > button.copy.copied:before,
91
+ .shiki-code[class*=language-] > button.copy:hover.copied:before {
92
+ position: relative;
93
+ top: -1px;
94
+ display: flex;
95
+ justify-content: center;
96
+ align-items: center;
97
+ border: 1px solid var(--shiki-code-copy-code-hover-border-color);
98
+ border-right: 0;
99
+ border-radius: 4px 0 0 4px;
100
+ padding: 0 10px;
101
+ width: fit-content;
102
+ height: 40px;
103
+ text-align: center;
104
+ font-size: 12px;
105
+ font-weight: 500;
106
+ color: var(--shiki-code-copy-code-active-text);
107
+ background-color: var(--shiki-code-copy-code-hover-bg);
108
+ white-space: nowrap;
109
+ content: var(--shiki-code-copy-copied-text-content);
110
+ transform: translate(calc(-100% - 1px));
111
+ }
112
+ .shiki-code[class*=language-] > span.lang {
113
+ position: absolute;
114
+ top: 2px;
115
+ right: 8px;
116
+ z-index: 2;
117
+ font-size: 12px;
118
+ font-weight: 500;
119
+ -webkit-user-select: none;
120
+ user-select: none;
121
+ color: var(--shiki-code-lang-color);
122
+ transition: color 0.4s, opacity 0.4s;
123
+ }
124
+ .shiki-code[class*=language-]:hover > button.copy + span.lang,
125
+ .shiki-code[class*=language-] > button.copy:focus + span.lang {
126
+ opacity: 0;
127
+ }
128
+ .shiki-code[class*=language-].theme-dark {
129
+ --shiki-code-line-diff-add-color: #3dd68c;
130
+ --shiki-code-line-diff-add-symbol-color: #3dd68c;
131
+ --shiki-code-line-diff-remove-color: hsla(349.72, 89.16%, 60.2%, 0.16);
132
+ --shiki-code-line-diff-remove-symbol-color: hsl(357.62, 39.92%, 50.39%);
133
+ --shiki-code-line-line-number-color: hsla(198.18, 13.36%, 80%, 0.7);
134
+ }
135
+ .shiki-code[class*=language-] pre.shiki .diff {
136
+ all: unset;
137
+ }
138
+ .shiki-code[class*=language-] pre.shiki code .diff.remove {
139
+ background-color: var(--shiki-code-line-diff-remove-color, rgba(244, 63, 94, 0.14));
140
+ opacity: 0.7;
141
+ }
142
+ .shiki-code[class*=language-] pre.shiki code .diff.add {
143
+ background-color: rgba(16, 185, 129, 0.14);
144
+ }
145
+ .shiki-code[class*=language-] pre.shiki code .diff.add:before {
146
+ content: "+";
147
+ color: var(--shiki-code-line-diff-add-symbol-color, #18794e);
148
+ }
149
+ .shiki-code[class*=language-] pre.shiki code .diff.remove:before {
150
+ content: "-";
151
+ color: var(--shiki-code-line-diff-remove-symbol-color, hsl(357.62, 39.92%, 50.39%));
152
+ }
153
+ .shiki-code[class*=language-] pre.shiki code .diff:before {
154
+ width: 2.5em;
155
+ text-align: left;
156
+ padding-left: 10px;
157
+ }
158
+ .shiki-code[class*=language-] pre.shiki code .diff {
159
+ box-sizing: border-box;
160
+ transition: background-color 0.5s;
161
+ margin: 0 -24px;
162
+ padding: 0 24px;
163
+ width: calc(100% + 48px);
164
+ display: inline-block;
165
+ }
166
+ .shiki-code[class*=language-].line-numbers code {
167
+ counter-reset: step;
168
+ counter-increment: step 0;
169
+ }
170
+ .shiki-code[class*=language-].line-numbers code .line::before {
171
+ content: counter(step);
172
+ counter-increment: step;
173
+ display: inline-block;
174
+ text-align: right;
175
+ color: var(--shiki-code-line-line-number-color, hsla(198.18, 13.36%, 51.57%, 0.7));
176
+ width: 2.5em;
177
+ text-align: left;
178
+ padding-left: 10px;
179
+ }
@@ -0,0 +1,3 @@
1
+ __all__ = ["duckdb"]
2
+
3
+ from ._duckdb import _facade as duckdb
@@ -0,0 +1,23 @@
1
+ from instaui import ui
2
+ from ._types import TFilters
3
+
4
+
5
+ class DataSourceElement(ui.element, esm="./data_source.js"):
6
+ def __init__(
7
+ self,
8
+ ):
9
+ super().__init__()
10
+
11
+ self._ele_ref = ui.element_ref()
12
+ self.element_ref(self._ele_ref)
13
+
14
+ self.filters: TFilters = ui.state({})
15
+
16
+ self.on(
17
+ "filter-changed",
18
+ ui.js_event(
19
+ inputs=[ui.event_context.e()],
20
+ outputs=[self.filters],
21
+ code="v=> v.filters",
22
+ ),
23
+ )
@@ -0,0 +1,221 @@
1
+ from pathlib import Path
2
+ from typing import Dict, TypeVar
3
+ import itertools
4
+ from instaui import ui, arco
5
+ from ._base import DataSourceElement
6
+ from ._types import TFilters, TQueryStrInfo
7
+
8
+ try:
9
+ import pandas
10
+ import duckdb
11
+ except ImportError as e:
12
+ raise e
13
+
14
+
15
+ TElementClass = TypeVar("TElementClass", bound=ui.element)
16
+
17
+
18
+ class DuckdbDataFrameSource:
19
+ QUERY_ID: int = 0
20
+
21
+ def __init__(
22
+ self,
23
+ table_name: str,
24
+ ):
25
+ super().__init__()
26
+
27
+ self._element = DataSourceElement()
28
+ self._conn = duckdb.connect(":default:", read_only=False)
29
+ self._table_name = table_name
30
+
31
+ def _generate_query_id(self):
32
+ self.QUERY_ID += 1
33
+ return self.QUERY_ID
34
+
35
+ def __getitem__(self, field: str):
36
+ def use_fn(cls: type[TElementClass]) -> TElementClass:
37
+ if issubclass(cls, arco.select):
38
+ return self.__apply_select(field)(cls)
39
+
40
+ if issubclass(cls, arco.input):
41
+ return self.__apply_input(field)(cls)
42
+
43
+ raise NotImplementedError(f"Not supported component:{cls.__name__}")
44
+
45
+ return use_fn
46
+
47
+ def __query_distinct_field_values(
48
+ self, field: str, query_id: int, order_sql: str = ""
49
+ ):
50
+ @ui.computed(inputs=[self.__query_str_info(field, query_id), field, order_sql])
51
+ def query_distinct_field_values_computed(
52
+ with_filters_info: TQueryStrInfo, field: str, order_sql: str
53
+ ):
54
+ sql = f"with cte as ({with_filters_info['sql']}) select distinct {field} from cte {order_sql}"
55
+
56
+ local_con = self._conn.cursor()
57
+
58
+ query = local_con.sql(sql, params=with_filters_info["params"])
59
+ return list(itertools.chain(*query.fetchall()))
60
+
61
+ return query_distinct_field_values_computed
62
+
63
+ def __apply_select(self, field: str):
64
+ def use_fn(cls: type[arco.select]) -> arco.select:
65
+ query_id = self._generate_query_id()
66
+ element = cls(
67
+ self.__query_distinct_field_values(
68
+ field=field, query_id=query_id, order_sql=f"order by {field}"
69
+ )
70
+ )
71
+
72
+ on_change = ui.js_event(
73
+ inputs=[ui.event_context.e(), field, query_id],
74
+ outputs=[self._element._ele_ref],
75
+ code=r"""(value,field,query_id) => {
76
+ if (value) {
77
+ return {method: 'addFilter', args:[{field, expr: `${field}= ?`,value,query_id}]};
78
+ }
79
+
80
+ return {method:'removeFilter', args:[{field,query_id}]};
81
+ }""",
82
+ )
83
+
84
+ element.on_change(on_change)
85
+
86
+ return element
87
+
88
+ return use_fn
89
+
90
+ def __apply_input(self, field: str):
91
+ def use_fn(cls: type[arco.input]) -> arco.input:
92
+ query_id = self._generate_query_id()
93
+ element = cls()
94
+
95
+ on_change = ui.js_event(
96
+ inputs=[ui.event_context.e(), field, query_id],
97
+ outputs=[self._element._ele_ref],
98
+ code=r"""(value,field,query_id) => {
99
+ if (value) {
100
+ value = `%${value.trim()}%`
101
+ return {method: 'addFilter', args:[{field, expr: `${field} like ?`,value,replace:true,query_id}]};
102
+ }
103
+
104
+ return {method:'removeFilter', args:[{field,query_id}]};
105
+ }""",
106
+ )
107
+
108
+ element.on_input(on_change)
109
+
110
+ return element
111
+
112
+ return use_fn
113
+
114
+ def __query_str_info(self, target_field: str = "", query_id: int = -1):
115
+ @ui.computed(inputs=[self._element.filters, target_field, query_id])
116
+ def query_str_computed(filters: TFilters, target_field: str, query_id: int):
117
+ if not filters:
118
+ return {
119
+ "sql": f"select * from {self._table_name}",
120
+ "params": [],
121
+ }
122
+ else:
123
+ filter_exprs = []
124
+
125
+ if target_field:
126
+ target_key = f"{target_field}-{query_id}"
127
+ without_target_exprs = (
128
+ exprs for key, exprs in filters.items() if key != target_key
129
+ )
130
+ filter_exprs = list(itertools.chain(*without_target_exprs))
131
+ else:
132
+ filter_exprs = list(itertools.chain(*filters.values()))
133
+
134
+ where_stem = " and ".join(info["expr"] for info in filter_exprs)
135
+ if where_stem:
136
+ where_stem = f" where {where_stem}"
137
+ return {
138
+ "sql": f"select * from {self._table_name}{where_stem}",
139
+ "params": [info["value"] for info in filter_exprs],
140
+ }
141
+
142
+ return query_str_computed
143
+
144
+ def query_str(self):
145
+ return ui.js_computed(
146
+ inputs=[self.__query_str_info()],
147
+ code=r"""info=>{
148
+ const {sql,params} = info;
149
+ let currentIndex = 0;
150
+ return sql.replace(/\?/g, function () {
151
+ if (currentIndex >= params.length) {
152
+ throw new Error('Not enough parameters provided for the SQL statement.');
153
+ }
154
+ return JSON.stringify(params[currentIndex++]);
155
+ });
156
+ }""",
157
+ )
158
+
159
+ def filters(self):
160
+ return self._element.filters
161
+
162
+ def __apply_table(self, *, sql: str):
163
+ def use_fn(cls: type[arco.table]) -> arco.table:
164
+ @ui.computed(inputs=[self.__query_str_info(), sql])
165
+ def table_query(with_filters_into: TQueryStrInfo, sql: str):
166
+ sql = f"with cte as ({with_filters_into['sql']}) {sql}"
167
+
168
+ local_con = self._conn.cursor()
169
+
170
+ query = local_con.sql(sql, params=with_filters_into["params"])
171
+ columns = query.columns
172
+ values = query.fetchall()
173
+
174
+ real_cols = [{"title": col, "dataIndex": col} for col in columns]
175
+
176
+ real_values = [
177
+ {col: val for col, val in zip(columns, row)} for row in values
178
+ ]
179
+
180
+ return {
181
+ "columns": real_cols,
182
+ "data": real_values,
183
+ }
184
+
185
+ element = cls(
186
+ data=ui.js_computed(inputs=[table_query], code=r"v=> v ? v.data : []"),
187
+ columns=ui.js_computed(
188
+ inputs=[table_query], code=r"v=> v ? v.columns : []"
189
+ ),
190
+ )
191
+
192
+ return element
193
+
194
+ return use_fn
195
+
196
+ def __call__(self, cls: type[arco.table], *, sql: str = "select * from cte"):
197
+ return self.__apply_table(sql=sql)(cls)
198
+
199
+ def query_table(self, *, sql: str):
200
+ return self.__apply_table(sql=sql)
201
+
202
+
203
+ class Facade:
204
+ def __call__(self, db: Path):
205
+ self.db = db
206
+ raise NotImplementedError()
207
+
208
+ @classmethod
209
+ def from_pandas(
210
+ cls, dataframe: "pandas.DataFrame", *, table_name: str = "df"
211
+ ) -> DuckdbDataFrameSource:
212
+ ds = DuckdbDataFrameSource(table_name)
213
+
214
+ cursor = ds._conn.cursor()
215
+ cursor.execute(
216
+ f"create table if not exists {table_name} as select * from dataframe"
217
+ )
218
+ return ds
219
+
220
+
221
+ _facade = Facade()
@@ -0,0 +1,15 @@
1
+ from typing import Any, Dict, List
2
+ from typing_extensions import TypedDict
3
+
4
+
5
+ class TFilterInfo(TypedDict):
6
+ expr: str
7
+ value: Any
8
+
9
+
10
+ TFilters = Dict[str, List[TFilterInfo]]
11
+
12
+
13
+ class TQueryStrInfo(TypedDict):
14
+ sql: str
15
+ params: List[Any]
@@ -0,0 +1,50 @@
1
+
2
+ export default {
3
+ props: [],
4
+
5
+ setup(props, { emit, expose }) {
6
+ const filters = new Map()
7
+
8
+ function addFilter(filter) {
9
+ const { field, expr, value, replace = true, query_id } = filter
10
+ const key = `${field}-${query_id}`
11
+
12
+ if (!filters.has(key)) {
13
+ filters.set(key, [])
14
+ }
15
+
16
+ const info = { expr, value }
17
+
18
+ if (replace) {
19
+ filters.set(key, [info])
20
+ } else {
21
+ filters.get(key).push(info)
22
+ }
23
+ emit("filter-changed", { filters: Object.fromEntries(filters.entries()), target: field, query_id })
24
+ }
25
+
26
+ function removeFilter(info) {
27
+ const { field, query_id } = info
28
+ const key = `${field}-${query_id}`
29
+
30
+ filters.delete(key)
31
+ emit("filter-changed", { filters: Object.fromEntries(filters.entries()), target: field, query_id })
32
+ }
33
+
34
+
35
+
36
+ function test(count) {
37
+ console.log('test', count)
38
+ }
39
+
40
+ expose({
41
+ test,
42
+ addFilter,
43
+ removeFilter,
44
+ })
45
+
46
+
47
+ },
48
+
49
+
50
+ }
@@ -18,7 +18,7 @@ def create_router(app: FastAPI):
18
18
 
19
19
 
20
20
  async def event_generator(
21
- request: Request, connection_id: str, interval_heart_beat_sec: int = 2
21
+ request: Request, connection_id: str, interval_heart_beat_sec: float = 0.8
22
22
  ):
23
23
  logger.debug("debug sse started")
24
24
  task_event = asyncio.Event()