arrmatura 4.2.2 → 5.0.2

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 (93) hide show
  1. package/README.md +30 -25
  2. package/commons/auth/UserService.ts +107 -0
  3. package/commons/auth/index.ts +4 -0
  4. package/commons/auth/user.xml +66 -0
  5. package/commons/components/buttons.xml +23 -0
  6. package/commons/components/index.ts +13 -0
  7. package/commons/components/inputs.xml +33 -0
  8. package/commons/components/layouts.xml +77 -0
  9. package/commons/components/media.xml +21 -0
  10. package/commons/components/modal.xml +37 -0
  11. package/commons/components/navigation.xml +59 -0
  12. package/commons/components/popups.xml +12 -0
  13. package/commons/components/searchbar.xml +40 -0
  14. package/commons/components/table.xml +120 -0
  15. package/commons/components/toasts.xml +13 -0
  16. package/commons/components/viewport.xml +48 -0
  17. package/commons/forms/FieldItem.xml +20 -0
  18. package/commons/forms/FormController.ts +73 -0
  19. package/commons/forms/Item.ts +68 -0
  20. package/commons/forms/ItemCollection.ts +152 -0
  21. package/commons/forms/ItemController.ts +62 -0
  22. package/commons/forms/MetadataService.ts +45 -0
  23. package/commons/forms/MultiEnumField.xml +44 -0
  24. package/commons/forms/MultivalueController.ts +49 -0
  25. package/commons/forms/SmartareaField.xml +51 -0
  26. package/commons/forms/SuggestionController.ts +80 -0
  27. package/commons/forms/SuggestionField.xml +28 -0
  28. package/commons/forms/fields.xml +138 -0
  29. package/commons/forms/form.xml +37 -0
  30. package/commons/forms/index.ts +29 -0
  31. package/commons/index.ts +6 -0
  32. package/commons/pipes/index.ts +21 -0
  33. package/commons/pipes/showCounts.ts +16 -0
  34. package/commons/services/ErrorHandlingService.ts +11 -0
  35. package/commons/services/FirebaseService.ts +185 -0
  36. package/commons/services/GSheetsService.ts +92 -0
  37. package/commons/services/HeartbeatService.ts +35 -0
  38. package/commons/services/Invoke.ts +13 -0
  39. package/commons/services/JsonpService.ts +18 -0
  40. package/commons/services/Loader.ts +17 -0
  41. package/commons/services/LocalStorage.ts +46 -0
  42. package/commons/services/NavigationService.ts +55 -0
  43. package/commons/services/Service.ts +68 -0
  44. package/commons/services/ServiceWorker.ts +111 -0
  45. package/commons/services/ToastService.ts +49 -0
  46. package/commons/services/index.ts +14 -0
  47. package/core/Arrmatura.ts +79 -0
  48. package/core/CNode.ts +112 -0
  49. package/core/Component.ts +431 -0
  50. package/core/Platform.ts +3 -0
  51. package/core/cnodes/composition.ts +100 -0
  52. package/core/cnodes/conditionals.ts +51 -0
  53. package/core/cnodes/elementary.ts +45 -0
  54. package/core/cnodes/iterations.ts +94 -0
  55. package/core/cnodes/routing.ts +25 -0
  56. package/core/compileNode.ts +39 -0
  57. package/core/expression.ts +73 -0
  58. package/core/index.ts +2 -0
  59. package/core/register.ts +43 -0
  60. package/core/utils.ts +25 -0
  61. package/core-web/WebPlatform.ts +25 -0
  62. package/core-web/attributes.ts +197 -0
  63. package/core-web/elements.ts +64 -0
  64. package/core-web/index.ts +19 -0
  65. package/core-web/reflow.ts +30 -0
  66. package/core-web/type.ts +19 -0
  67. package/docs/index.js +191 -4077
  68. package/lib/arrayGroupBy.ts +19 -0
  69. package/lib/arraySortBy.ts +49 -0
  70. package/lib/arrayToObject.ts +18 -0
  71. package/lib/codus.ts +25 -0
  72. package/lib/consts.ts +3 -0
  73. package/lib/createListeners.ts +12 -0
  74. package/lib/curry.ts +8 -0
  75. package/lib/dateFormat.ts +69 -0
  76. package/lib/dateOf.ts +31 -0
  77. package/lib/dateParseISO8601.ts +27 -0
  78. package/lib/fx.ts +62 -0
  79. package/lib/guid.ts +7 -0
  80. package/lib/index.ts +19 -0
  81. package/lib/l10n.ts +40 -0
  82. package/lib/nextId.ts +9 -0
  83. package/lib/noop.ts +8 -0
  84. package/lib/obj.ts +62 -0
  85. package/lib/predicat.ts +26 -0
  86. package/lib/resources.ru.ts +20 -0
  87. package/lib/resources.ts +20 -0
  88. package/lib/scalar.ts +25 -0
  89. package/lib/str.ts +76 -0
  90. package/lib/urls.ts +91 -0
  91. package/lib/xml.ts +117 -0
  92. package/package.json +17 -8
  93. package/docs/index.js.map +0 -1
package/README.md CHANGED
@@ -1,49 +1,54 @@
1
1
  # Arrmatura
2
2
 
3
- `Arrmatura` introduces an ultimate `specification-as-a-code` approach to develop a data-driven systems by defining and composing components in a declarative way.
4
-
5
- `Arrmatura` is intended to be
3
+ `Arrmatura` is a mimimalistic component framework that designed to be:
6
4
 
7
5
  - declarative and codeless
6
+ - reactive and functional
8
7
  - non-obtrusive, platform-independent
9
- - reactive and functional oriented
10
8
  - easy to learn and get started.
11
9
 
12
- `Arrmatura` is a minimalistic UI framework, that enriches the pure HTML with components, arrows and pipes.
13
-
14
- Born-for-dom, it is also may be adopted to develop wide range of modular component-based applications.
15
-
16
10
  # Get Started
17
11
 
18
12
  npm i arrmatura
19
13
 
20
- ```javascript
21
- import { launch } from "arrmatura";
14
+ ./templates.xml
15
+
16
+ ```xml
17
+ <component id="Application">
18
+ <Main name="Joe"/>
19
+ </component>
22
20
 
23
- const components = `<component id="Footer">
24
- <Button title=":send_title|upper">
25
- </component>`;
21
+ <component id="Main">
22
+ <Button title="{:greeting}, {name|upper}!">
23
+ </component>
24
+ ```
25
+
26
+ index.ts
26
27
 
27
- launch({
28
- types: [Application, SomeService, components],
29
- template: "<Application />",
28
+ ```javascript
29
+ import { arrmatura } from 'arrmatura';
30
+ import templates from './templates.xml';
31
+
32
+ arrmatura('<Application />', {
33
+ types: [templates],
30
34
  resources: {
31
- send_title: "Send",
35
+ greeting: 'Hello',
32
36
  },
33
- pipes: {
37
+ functions: {
34
38
  upper: (x) => x.toUpperCase(),
35
39
  },
36
40
  });
37
41
  ```
38
42
 
39
- Please take a look into [Todo App](https://alitskevich.github.io/arrmatura/todo.html) to get very basic insight how it works.
40
-
41
43
  # Documentation
42
44
 
43
- - [Glossary](md/GLOSSARY.md)
44
- - [Templates](md/TEMPLATE.md)
45
- - [Custom components](md/CUSTOM.md)
45
+ - [Glossary](manuals/GLOSSARY.md)
46
+ - [Templates](manuals/TEMPLATE.md)
47
+ - [Custom components](manuals/CUSTOM.md)
46
48
 
47
- # Usages
49
+ # Samples
48
50
 
49
- - [Grodno.co](https://grodno.co)
51
+ - [TodoMVC](https://alitskevich.github.io/arrmatura/todo.html) ([source](https://github.com/alitskevich/arrmatura/blob/master/docs/todo.html))
52
+ - [Tasks list](https://alitskevich.github.io/arrmatura/task.html) ([source](https://github.com/alitskevich/arrmatura/tree/master/app-task))
53
+ - [Game Solver](https://dlitskevich.github.io/solver/) ([source](https://github.com/dlitskevich/solver/tree/master/app))
54
+ - [Input Templates](https://alitskevich.github.io/templain/) ([source](https://github.com/alitskevich/templain/tree/master/app))
@@ -0,0 +1,107 @@
1
+ import { Service } from '../services/Service';
2
+ import { urlAppendParams } from 'urls';
3
+ import { LocalStorage } from '../services/LocalStorage';
4
+
5
+ export class UserService extends Service {
6
+ url: string = '';
7
+ kind: string = '$user';
8
+ local: LocalStorage = new LocalStorage('local');
9
+ token: any;
10
+ $info: unknown;
11
+
12
+ init() {
13
+ return this.syncUserInfo();
14
+ }
15
+
16
+ syncUserInfo() {
17
+ const token = this.token || this.local?.get('$token');
18
+
19
+ return !token
20
+ ? null
21
+ : {
22
+ isLoading: true,
23
+ '*': fetch(urlAppendParams(this.url, { action: 'user', token }), { redirect: 'follow' })
24
+ .then((res) => res.json())
25
+ .then(({ info, error }) => {
26
+ if (error) throw error;
27
+ this.log('sync' + this.kind, info);
28
+ this.local?.set('$token', token);
29
+ return { info, isLoading: false };
30
+ })
31
+ .catch((err) => {
32
+ this.toast({ mode: 'error', message: 'Ошибка: ' + JSON.stringify(err?.message || err || 'unknown') });
33
+ return { info: null, isLoading: false };
34
+ }),
35
+ };
36
+ }
37
+
38
+ set info(info: unknown) {
39
+ this.$info = info;
40
+ this.local?.set(this.kind, info);
41
+ }
42
+
43
+ get info() {
44
+ const info = this.$info || this.local?.get(this.kind);
45
+ return info;
46
+ }
47
+
48
+ get isSignedIn() {
49
+ return this.info?.id;
50
+ }
51
+
52
+ async update(delta: Delta) {
53
+ const now = Date.now();
54
+ const { since, items: items0 = [] } = this.local?.get(this.kind) || { since: 0, items: {} };
55
+
56
+ this.log('update', delta);
57
+
58
+ return {
59
+ busy: true,
60
+ '*': fetch(this.url, {
61
+ method: 'POST',
62
+ mode: 'cors',
63
+ redirect: 'follow',
64
+ body: JSON.stringify({ action: 'upsert', delta }),
65
+ })
66
+ .then((res) => res.json())
67
+ .then(({ id, error }) => {
68
+ if (error) throw error;
69
+ // items: items1 }
70
+ this.log('update sync' + this.kind, now, id);
71
+ // const items = { ...items0, ...arrayToObject(items1) };
72
+ this.toast('Сохранено успешно');
73
+
74
+ // this.local?.set(this.kind, { since: now, items });
75
+ return { busy: false }; //items,
76
+ })
77
+ .catch((err) => {
78
+ this.toast({ mode: 'error', message: 'Ошибка: update ' + JSON.stringify(err?.message || err || 'unknown') });
79
+ return { busy: false };
80
+ }),
81
+ };
82
+ }
83
+
84
+ onUpdate(data, { info }) {
85
+ return {
86
+ info: { ...info, ...data },
87
+ };
88
+ }
89
+
90
+ onLogin() {
91
+ return {
92
+ info: { id: 1, name: 'Me' },
93
+ };
94
+ }
95
+
96
+ onShowProfile(showProfile = false) {
97
+ return {
98
+ showProfile,
99
+ };
100
+ }
101
+
102
+ onLogout() {
103
+ return {
104
+ info: { id: 0, name: 'Me222' },
105
+ };
106
+ }
107
+ }
@@ -0,0 +1,4 @@
1
+ import user from './user.xml';
2
+ import { UserService } from './UserService';
3
+
4
+ export default [user, UserService];
@@ -0,0 +1,66 @@
1
+ <component id="UserBar">
2
+ <div class="float-right">
3
+ <UserLoading ui:if="<-user.isLoading">
4
+ <ui:else>
5
+ <NoUserPanel ui:if="<-user.isSignedIn|not">
6
+ <ui:else>
7
+ <UserPanel ui:props="<-user.info" defaultImage="assets/img/avatar-1.png"/>
8
+ </ui:else>
9
+ </NoUserPanel>
10
+ </ui:else>
11
+ </UserLoading>
12
+ </div>
13
+ </component>
14
+
15
+ <component id="UserLoading">
16
+ <div class="tile tile-centered">
17
+ <div class="tile-action">
18
+ <div class="dropdown dropdown-right">
19
+ <a class="btn btn-link dropdown-toggle" tabindex="0">
20
+ <div class="mx-2 loading"></div>
21
+ </a>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </component>
26
+
27
+ <component id="UserPanel">
28
+ <div class="tile tile-centered">
29
+ <div class="tile-icon">
30
+ <div class="example-tile-icon c-hand" click="-> user.showProfile|truthy">
31
+ <figure class="avatar">
32
+ <img src="{image|or:@defaultImage}" alt="{name}" />
33
+ </figure>
34
+ </div>
35
+ </div>
36
+ <div class="tile-action">
37
+ <div class="dropdown dropdown-right">
38
+ <a class="btn btn-link dropdown-toggle" tabindex="0">
39
+ <i class="icon icon-more-vert"></i >
40
+ </a>
41
+ <ul class="menu">
42
+ <li class="menu-item">
43
+ <a click="-> user.logout">⏹️Vyxod</a>
44
+ </li>
45
+ </ul>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </component>
50
+
51
+ <component id="NoUserPanel">
52
+ <div class="tile tile-centered">
53
+ <div class="tile-action">
54
+ <div class="dropdown dropdown-right">
55
+ <a class="btn btn-link dropdown-toggle" tabindex="0">
56
+ <i class="icon icon-more-vert"></i >
57
+ </a>
58
+ <ul class="menu">
59
+ <li class="menu-item">
60
+ <a click="-> user.login">▶️Vxod</a>
61
+ </li>
62
+ </ul>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </component>
@@ -0,0 +1,23 @@
1
+ <component id="Btn">
2
+ <button class="
3
+ btn btn-{mode}
4
+ {primary|then:btn-primary}
5
+ {disabled|or:@busy|then:disabled}
6
+ {class}
7
+ {large|then:btn-lg}
8
+ {link|then:btn-link}
9
+ c-hand
10
+ " style="{style}" data={data} click="{action}">
11
+ <span ui:if="{busy}" class="mx-2">
12
+ <i class="loading"></i>
13
+ </span>
14
+ <Icon ui:if="{icon}" bundle="{iconBundle}" type="{icon}" class="mr-2" />
15
+ <span ui:if="{title}" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{title}</span>
16
+ </button>
17
+ </component>
18
+
19
+ <component id="FAB">
20
+ <button class="btn {tooltip|then:tooltip} tooltip-left fixed bg-error s-circle centroid c-hand {class} {disabled|or:@busy|then:disabled} {busy|then:loading}" style="position: fixed; border: none; right: 1.5rem; bottom: 1.5rem; width: 2.5rem; height: 2.5rem;" data="{data}" data-tooltip="{tooltip|or:}" click="{action}">
21
+ <Icon type="{icon|or:plus}" />
22
+ </button>
23
+ </component>
@@ -0,0 +1,13 @@
1
+ import buttons from './buttons.xml';
2
+ import table from './table.xml';
3
+ import inputs from './inputs.xml';
4
+ import media from './media.xml';
5
+ import modal from './modal.xml';
6
+ import navigation from './navigation.xml';
7
+ import layouts from './layouts.xml';
8
+ import viewport from './viewport.xml';
9
+ import toasts from './toasts.xml';
10
+ import searchbar from './searchbar.xml';
11
+ import popups from './popups.xml';
12
+
13
+ export default [buttons, media, table, modal, navigation, toasts, viewport, layouts, inputs, searchbar, popups];
@@ -0,0 +1,33 @@
1
+ <component id="Select">
2
+ <select class="{class}" change="{change}" multiple="{multiple}" disabled="{disabled}" data="{data}">
3
+ <option selected="{value|not}" value="" ui:if="{value|not|or:@emptyCaption}">{emptyCaption}</option>
4
+ <option ui:for="option of options" selected="{option.id|equals:@value}" value="{option.id}">{option.name}</option>
5
+ </select>
6
+ </component>
7
+
8
+ <component id="RadioGroup">
9
+ <div class="{class}">
10
+ <label class="form-radio" ui:for="option of options">
11
+ <input type="radio" name="{id|or:rg}" value="{option.id}" checked="{option.id|equals:@value}" change="{change}" data="{data}" disabled="{disabled}" />
12
+ <i class="form-icon"></i>{option.name}
13
+ </label>
14
+ </div>
15
+ </component>
16
+
17
+ <component id="Dropdown">
18
+ <div class="dropdown">
19
+ <a href="#" class="btn btn-link dropdown-toggle" tabindex="0">
20
+ {data|selectedName}<i class="icon icon-caret"></i>
21
+ </a>
22
+ <!-- menu component -->
23
+ <ul class="menu" style="right: 0; left: auto">
24
+ <li ui:for="item of data" class="menu-item {item.id|equals:@value|then:active}" data-id="{item.id}" data-name="{item.name}" click="{change}">
25
+ <a>{item.name}</a>
26
+ </li>
27
+ </ul>
28
+ </div>
29
+ </component>
30
+
31
+ <component id="DateTimeInput">
32
+ <input class="form-input flatpickr-input" init="{:support.initFlatpickr}" disabled="{disabled}" type="text" placeholder="{placeholder}" value="{value|support.setFlatpickrValue}" change="{change}" />
33
+ </component>
@@ -0,0 +1,77 @@
1
+ <component id="Container">
2
+ <div class="container {class}" style="max-width: 720px;">
3
+ <a name="top"></a>
4
+ <ui:slot />
5
+ </div>
6
+ </component>
7
+
8
+ <component id="Panel">
9
+ <h6 class="mt-2 pt-2 px-2 text-gray" ui:if="caption">{caption}</h6>
10
+ <div class="panel {class}" style="{style}">
11
+ <small class="p-2 bg-secondary" ui:if="{hint}">{hint}</small>
12
+ <div class="panel-header" ui:if="slot(title)">
13
+ <div class="panel-title">
14
+ <ui:slot id="title" key="panel-title" />
15
+ </div>
16
+ </div>
17
+ <div class="panel-nav" ui:if="slot(nav)">
18
+ <ui:slot id="nav" />
19
+ </div>
20
+ <div class="panel-body p-2">
21
+ <ui:slot />
22
+ </div>
23
+ <div class="panel-footer" ui:if="slot(footer)">
24
+ <ui:slot id="footer" />
25
+ </div>
26
+ </div>
27
+ </component>
28
+
29
+ <component id="Tile">
30
+ <div class="tile {centered|then:tile-centered} m-2 {class}">
31
+ <div class="tile-icon" ui:if="{image}">
32
+ <Avatar src="{image}" />
33
+ </div>
34
+ <div class="tile-icon" ui:if="{icon}">
35
+ <Icon type="{icon}" />
36
+ </div>
37
+ <div class="tile-content">
38
+ <div class="tile-title text-bold" ui:if="{title}">{title}</div>
39
+ <div class="tile-subtitle" ui:if="{subtitle}">{subtitle}</div>
40
+ <ui:slot />
41
+ </div>
42
+ <div class="tile-action btn-group" ui:if="slot(actions)">
43
+ <ui:slot id="actions" />
44
+ </div>
45
+ </div>
46
+ </component>
47
+
48
+ <component id="Card">
49
+ <div class="card" style="{style}">
50
+ <div class="card-image" ui:if="{image}">
51
+ <img src="{image}" class="img-responsive" />
52
+ </div>
53
+ <div class="card-header">
54
+ <a ui:if="{title}" href="{link}">
55
+ <h5 class="card-title">{title}</h5>
56
+ </a>
57
+ <div ui:if="{subtitle}" class="card-subtitle text-gray">{subtitle}</div>
58
+ <ui:slot id="header" />
59
+ </div>
60
+ <div class="card-body">
61
+ <ui:slot />
62
+ </div>
63
+ <div class="card-footer">
64
+ <ui:slot id="footer" />
65
+ </div>
66
+ </div>
67
+ </component>
68
+
69
+ <component id="Hero">
70
+ <div class="hero bg-dark p-0">
71
+ <div class="hero-body px-2">
72
+ <h1>{title}</h1>
73
+ </div>
74
+ </div>
75
+ </component>
76
+
77
+
@@ -0,0 +1,21 @@
1
+ <component id="Icon">
2
+ <i class="icon icon-{type} {class}" style="{style}" data="{data}" click="{click}"></i>
3
+ </component>
4
+
5
+ <component id="Img">
6
+ <img src="{src|or:@default}" alt="{alt}" class="img {class}" style="{style}" />
7
+ </component>
8
+
9
+ <component id="ImgLogo">
10
+ <img src="{src}" class="{class}" error="->" data-src="/assets/logo.jpg" />
11
+ </component>
12
+
13
+ <component id="IFrame">
14
+ <iframe width="100%" height="450" frameborder="0" style="border: 0;" src="{src}" allowfullscreen="1"></iframe>
15
+ </component>
16
+
17
+ <component id="Avatar">
18
+ <figure class="avatar {large|then:avatar-lg}">
19
+ <img src="{src}" alt="{alt}" default="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />
20
+ </figure>
21
+ </component>
@@ -0,0 +1,37 @@
1
+ <component id="Modal">
2
+ <!--
3
+
4
+ Modal component:
5
+
6
+ Slots:
7
+ - header
8
+ - default
9
+ - footer
10
+
11
+ Properties:
12
+ - open: boolean
13
+ - close: procedure
14
+ - title: string
15
+ - mode: lg|sm
16
+
17
+ -->
18
+ <div class="modal modal-{mode} {open|then:active}">
19
+ <a class="modal-overlay" aria-label="Close" click="{close}"></a>
20
+ <div class="modal-container" style="padding:0;max-height: {mode|equals:lg|then:100:70}vh">
21
+ <div class="modal-header" style="padding-bottom:0;">
22
+ <a class="btn btn-clear float-right" aria-label=":close" click="{close}"></a>
23
+ <div class="modal-title h5" ui:if="{title}">{title}</div>
24
+ <ui:slot id="header" />
25
+ </div>
26
+ <div class="modal-body" style="">
27
+ <div class="content">
28
+ <ui:slot />
29
+ </div>
30
+ </div>
31
+ <div class="modal-footer">
32
+ <ui:slot id="footer" />
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </component>
37
+
@@ -0,0 +1,59 @@
1
+ <component id="Tabs">
2
+ <ul class="tab tab-block">
3
+ <li class="tab-item {item.id|equals:@value|then:active} c-hand" ui:for="item of items">
4
+ <a data-id="{item.id}" click="{change}">
5
+ <Icon ui:if="{item.icon}" type="{item.icon}" bundle="{item.iconBundle}" class="mx-2" />
6
+ {item.name|or:@item.id}
7
+ </a>
8
+ </li>
9
+ </ul>
10
+ </component>
11
+
12
+ <component id="BackButton">
13
+ <a class="mx-2" style="border: none; width: 1.5rem; z-index: 5" href="{href}">
14
+ <Icon type="back" />
15
+ </a>
16
+ </component>
17
+
18
+ <component id="Navbar">
19
+ <header class="navbar sticky {class} bg-secondary" style="min-height: 48px;flex-wrap: nowrap;margin:0;">
20
+ <section class="navbar-section">
21
+ <div class="m-2 flexoid items-center">
22
+ <ui:slot id="left" />
23
+ <h5 class="m-1 text-dark {badge|then:badge}" style="vertical-align: middle" data-badge="{badge}" ui:if="{caption}">{caption}</h5>
24
+ </div>
25
+ </section>
26
+ <section class="navbar-center" ui:if="{logo}">
27
+ <img src="{logo}" style="max-height: 44px" />
28
+ </section>
29
+ <section class="navbar-section flex-0 mx-2" ui:if="slot(right)">
30
+ <ui:slot id="right" />
31
+ </section>
32
+ </header>
33
+ </component>
34
+
35
+ <component id="PageRouter">
36
+ <ui:tag tag="{host|capitalize|or:Loader}Page" path={path} ui:props="{params}" params="{params}" />
37
+ </component>
38
+
39
+ <component id="LoaderPage">
40
+ <LoadingIndicator />
41
+ </component>
42
+
43
+ <component id="NavTree">
44
+ <ul class="nav">
45
+ <li class="nav-item {item.class}" ui:for="item of data">
46
+ <NavLink href="{item.id}">
47
+ <span>{item.name}</span>
48
+ <span ui:if="{item.label}" class="label label-error">{item.label}</span>
49
+ </NavLink>
50
+ <NavTree ui:if="{item.subs}" data="{item.subs}" />
51
+ </li>
52
+ </ul>
53
+ </component>
54
+
55
+ <component id="NavLink">
56
+ <a data-value="{href}" click="-> nav.hash" class="c-hand {class}">
57
+ <ui:slot />
58
+ </a>
59
+ </component>
@@ -0,0 +1,12 @@
1
+ <component id="Popover">
2
+ <div class="popover popover-right">
3
+ <ui:slot />
4
+ <div class="popover-container">
5
+ <div class="card">
6
+ <div class="card-header">
7
+ <ui:slot id="body" />
8
+ </div>
9
+ </div>
10
+ </div>
11
+ </div>
12
+ </component>
@@ -0,0 +1,40 @@
1
+ <component id="SearchBar">
2
+ <span class="ant-input-search ant-input-affix-wrapper">
3
+ <input placeholder="Поиск..." class="ant-input" type="text" value="{value}" enter="{action}" style="min-height: 40px" />
4
+ <span class="ant-input-suffix">
5
+ <i class="anticon anticon-search ant-input-search-icon" style="margin-top: 4px"></i>
6
+ </span>
7
+ </span>
8
+ </component>
9
+
10
+ <component id="SearchBarWithSuggestions">
11
+ <ui:fragment ui:if="opened.value">
12
+ <ui:then>
13
+ <div class="form-autocomplete mx-2">
14
+ <!-- autocomplete input container -->
15
+ <div class="form-autocomplete-input form-input input-sm">
16
+ <div class="input-group input-inline">
17
+ <input class="form-input" type="search" autofocus placeholder=":kluq_poshuku" keypress="{input}" value="{value}" style="max-width:120px;width:inherit" />
18
+ <i class="icon icon-cross m-2 c-hand" data-value="" click="{enter}" ui:if="value"></i>
19
+ <i class="icon icon-search m-2 c-hand" click="->opened|assignKeyValue:value:false" ui:if="value|not"></i>
20
+ </div>
21
+ </div>
22
+ <ul class="menu" style="min-width: 120px;max-height:7rem;overflow-y:auto;" ui:if="{suggestions}">
23
+ <li class="menu-item" ui:for="item of suggestions" data-value="{item.id}" click="{enter}">
24
+ <a>
25
+ <div class="tile tile-centered">
26
+ <div class="tile-content">{item.name}</div>
27
+ </div>
28
+ </a>
29
+ </li>
30
+ </ul>
31
+ </div>
32
+ </ui:then>
33
+ <ui:else>
34
+ <div class="mx-2" click="{open|bindArgs:true}">
35
+ <i class="icon icon-search m-2 c-hand" click="->opened|assignKeyValue:value:true"></i>
36
+ </div>
37
+ </ui:else>
38
+ </ui:fragment>
39
+
40
+ </component>