@onetype/framework 2.0.21 → 2.0.24

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 (131) hide show
  1. package/addons/core/assets/back/functions/import.js +24 -0
  2. package/addons/render/pages/front/events/click.js +1 -1
  3. package/addons/render/pages/front/functions/change.js +1 -1
  4. package/docs/architecture.md +58 -10
  5. package/docs/frontend.md +29 -12
  6. package/lib/items/elements/form/button/button.js +106 -0
  7. package/lib/items/elements/form/button/styles/base.css +176 -0
  8. package/lib/items/elements/form/button/styles/sizes.css +78 -0
  9. package/lib/items/elements/form/button/styles/variants.css +421 -0
  10. package/lib/items/elements/form/checkbox/checkbox.js +58 -0
  11. package/lib/items/elements/form/checkbox/styles/base.css +52 -0
  12. package/lib/items/elements/form/checkbox/styles/sizes.css +39 -0
  13. package/lib/items/elements/form/checkbox/styles/variants.css +121 -0
  14. package/lib/items/elements/form/field/field.css +96 -0
  15. package/lib/items/elements/form/field/field.js +40 -0
  16. package/lib/items/elements/form/input/input.css +111 -0
  17. package/lib/items/elements/form/input/input.js +79 -0
  18. package/lib/items/elements/form/input/styles/base.css +26 -0
  19. package/lib/items/elements/form/input/styles/sizes.css +15 -0
  20. package/lib/items/elements/form/input/styles/variants.css +98 -0
  21. package/lib/items/elements/form/radio/radio.js +58 -0
  22. package/lib/items/elements/form/radio/styles/base.css +48 -0
  23. package/lib/items/elements/form/radio/styles/sizes.css +36 -0
  24. package/lib/items/elements/form/radio/styles/variants.css +121 -0
  25. package/lib/items/elements/form/rating/rating.css +95 -0
  26. package/lib/items/elements/form/rating/rating.js +89 -0
  27. package/lib/items/elements/form/section/section.css +129 -0
  28. package/lib/items/elements/form/section/section.js +40 -0
  29. package/lib/items/elements/form/slider/slider.css +244 -0
  30. package/lib/items/elements/form/slider/slider.js +70 -0
  31. package/lib/items/elements/form/textarea/textarea.css +117 -0
  32. package/lib/items/elements/form/textarea/textarea.js +70 -0
  33. package/lib/items/elements/global/card/card.css +57 -0
  34. package/lib/items/elements/global/card/card.js +48 -0
  35. package/lib/items/elements/global/code/code.css +66 -0
  36. package/lib/items/elements/global/code/code.js +40 -0
  37. package/lib/items/elements/global/faq/faq.css +76 -0
  38. package/lib/items/elements/global/faq/faq.js +44 -0
  39. package/lib/items/elements/global/heading/heading.css +106 -0
  40. package/lib/items/elements/global/heading/heading.js +52 -0
  41. package/lib/items/elements/global/markdown/markdown.css +248 -0
  42. package/lib/items/elements/global/markdown/markdown.js +23 -0
  43. package/lib/items/elements/global/notice/notice.css +91 -0
  44. package/lib/items/elements/global/notice/notice.js +35 -0
  45. package/lib/items/elements/global/parameters/params.css +69 -0
  46. package/lib/items/elements/global/parameters/params.js +32 -0
  47. package/lib/items/elements/global/tabs/tabs.css +47 -0
  48. package/lib/items/elements/global/tabs/tabs.js +32 -0
  49. package/lib/items/elements/global/tags/tags.css +42 -0
  50. package/lib/items/elements/global/tags/tags.js +46 -0
  51. package/lib/items/elements/sections/footer/footer.css +205 -0
  52. package/lib/items/elements/sections/footer/footer.js +109 -0
  53. package/lib/items/elements/sections/hero/hero.css +100 -0
  54. package/lib/items/elements/sections/hero/hero.js +54 -0
  55. package/lib/items/elements/sections/navbar/navbar.css +80 -0
  56. package/lib/items/elements/sections/navbar/navbar.js +42 -0
  57. package/lib/items/elements/sections/stats/stats.css +34 -0
  58. package/lib/items/elements/sections/stats/stats.js +74 -0
  59. package/lib/items/elements/status/code/code.css +48 -0
  60. package/lib/items/elements/status/code/code.js +44 -0
  61. package/lib/items/elements/status/empty/empty.css +59 -0
  62. package/lib/items/elements/status/empty/empty.js +43 -0
  63. package/lib/items/elements/status/error/error.css +55 -0
  64. package/lib/items/elements/status/error/error.js +55 -0
  65. package/lib/items/elements/status/loading/loading.css +62 -0
  66. package/lib/items/elements/status/loading/loading.js +31 -0
  67. package/lib/load.js +83 -5
  68. package/lib/src/classes/addon/class.js +1 -1
  69. package/lib/src/classes/addon/mixins/store.js +8 -8
  70. package/lib/src/mixins/assets.js +65 -0
  71. package/lib/src/mixins/data.js +7 -2
  72. package/lib/src/onetype.js +4 -0
  73. package/lib/styles/classes/layout.css +36 -0
  74. package/lib/styles/classes/spacing.css +96 -0
  75. package/lib/styles/queries.css +6 -0
  76. package/lib/styles/reset.css +169 -0
  77. package/lib/styles/variables.css +71 -0
  78. package/package.json +3 -3
  79. package/addons/core/clients/LICENSE.txt +0 -40
  80. package/addons/core/clients/README.md +0 -123
  81. package/addons/core/database/README.md +0 -276
  82. package/addons/render/assets/back/README.md +0 -1
  83. package/addons/render/assets/back/functions/import.js +0 -45
  84. package/addons/render/items/js/#register/addon.js +0 -14
  85. package/addons/render/items/js/functions/count.js +0 -9
  86. package/addons/render/items/js/functions/get.js +0 -34
  87. package/addons/render/items/js/functions/groups.js +0 -16
  88. package/addons/render/items/js/functions/render.js +0 -44
  89. package/addons/render/items/js/item/catch/add.js +0 -18
  90. package/test/front/test.js +0 -56
  91. package/test.js +0 -55
  92. /package/addons/{render → core}/assets/back/addon.js +0 -0
  93. /package/addons/{render → core}/assets/back/functions/css.js +0 -0
  94. /package/addons/{render → core}/assets/back/functions/js.js +0 -0
  95. /package/addons/{render → core}/assets/back/functions/scan/directories.js +0 -0
  96. /package/addons/{render → core}/assets/back/functions/scan/files.js +0 -0
  97. /package/addons/{render → core}/assets/back/functions/utils/read.js +0 -0
  98. /package/addons/{render → core}/assets/back/functions/utils/transform.js +0 -0
  99. /package/addons/{render → core}/assets/back/items/commands/css.js +0 -0
  100. /package/addons/{render → core}/assets/back/items/commands/js.js +0 -0
  101. /package/addons/{render → core}/assets/back/items/html/css.js +0 -0
  102. /package/addons/{render → core}/assets/back/items/html/js.js +0 -0
  103. /package/addons/{render → core}/assets/back/load.js +0 -0
  104. /package/addons/core/database/front/{#register/addon.js → addon.js} +0 -0
  105. /package/addons/float/modals/front/js/{#register/addon.js → addon.js} +0 -0
  106. /package/addons/float/overlays/front/js/{#register/addon.js → addon.js} +0 -0
  107. /package/addons/float/popups/js/{#register/addon.js → addon.js} +0 -0
  108. /package/addons/float/toasts/{#register/addon.js → addon.js} +0 -0
  109. /package/addons/float/tooltips/{#register/addon.js → addon.js} +0 -0
  110. /package/addons/render/transforms/{front/js/#register/addon.js → addon.js} +0 -0
  111. /package/addons/render/transforms/{front/js/functions → functions}/load/assets.js +0 -0
  112. /package/addons/render/transforms/{front/js/items → items}/directives/transform.js +0 -0
  113. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/accordion}/accordion.js +0 -0
  114. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/area.js +0 -0
  115. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/bar.js +0 -0
  116. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/bubble.js +0 -0
  117. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/doughnut.js +0 -0
  118. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/line.js +0 -0
  119. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/pie.js +0 -0
  120. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/radar.js +0 -0
  121. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms}/chart/scatter.js +0 -0
  122. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/codeflask}/codeflask.js +0 -0
  123. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/codemirror}/codemirror.js +0 -0
  124. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/comparison}/comparison.js +0 -0
  125. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/heatmap}/heatmap.js +0 -0
  126. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/interact}/interact.js +0 -0
  127. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/particles}/particles.js +0 -0
  128. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/sparkline}/sparkline.js +0 -0
  129. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/swiper}/swiper.js +0 -0
  130. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/tabs}/tabs.js +0 -0
  131. /package/{addons/render/transforms/front/js/items/self → lib/items/transforms/typed}/typed.js +0 -0
@@ -0,0 +1,24 @@
1
+ import assets from '../addon.js';
2
+ import onetype from '#framework/load.js';
3
+
4
+ assets.Fn('import', function(modules)
5
+ {
6
+ for (let i = 0; i < modules.length; i++)
7
+ {
8
+ const entry = modules[i];
9
+ const registered = onetype.AssetsGet(entry);
10
+
11
+ if (registered)
12
+ {
13
+ if (registered.js)
14
+ {
15
+ assets.Item({ type: 'js', order: i, path: registered.js.path, ignore: registered.js.exclude || [] });
16
+ }
17
+
18
+ if (registered.css)
19
+ {
20
+ assets.Item({ type: 'css', order: i, path: registered.css.path, ignore: registered.css.exclude || [] });
21
+ }
22
+ }
23
+ }
24
+ });
@@ -23,5 +23,5 @@ document.addEventListener('click', (e) =>
23
23
 
24
24
  e.preventDefault();
25
25
 
26
- pages.Fn('change', match.page.Get('id'), match.parameters);
26
+ pages.Fn('change', match.page.Get('id'), match.parameters, { search: url.search });
27
27
  });
@@ -41,7 +41,7 @@ pages.Fn('change', function(target, parameters = {}, options = {})
41
41
 
42
42
  if(this.options.push !== false)
43
43
  {
44
- history.pushState(null, '', url);
44
+ history.pushState(null, '', url + (this.options.search || ''));
45
45
  }
46
46
 
47
47
  const result = this.Fn('open', this.id, this.parameters);
@@ -3,17 +3,27 @@
3
3
  ## File structure
4
4
 
5
5
  ```
6
- lib/ Core OneType class + 17 mixins
7
- load.js Entry point — creates OneType instance, handles signals
6
+ lib/ Core OneType class + mixins
7
+ load.js Entry point — creates OneType instance, registers all assets, handles signals
8
8
  src/
9
9
  onetype.js Main class (mixin-composed)
10
10
  mixins/ Addons, Emitter, Middleware, Data, DOM, Route,
11
- Function, Generate, Binaries, Helper, Cookie, and more
11
+ Function, Generate, Binaries, Helper, Cookie, Assets, and more
12
12
  classes/
13
13
  addon/ OneTypeAddon + mixins (fields, items, functions, find, render, store)
14
14
  classes/
15
15
  item/ OneTypeAddonItem + mixins (get, set, crud, functions, store)
16
16
  render/ OneTypeAddonRender + mixins (compile, dom, process, events)
17
+ styles/ Shared CSS (variables, reset, queries, utility classes)
18
+ items/
19
+ elements/ Shared UI elements (grouped, IDs are group-prefixed)
20
+ form/ button, checkbox, field, input, radio, rating, section, slider, textarea
21
+ global/ card, code, faq, heading, markdown, notice, parameters, tabs, tags
22
+ sections/ footer, hero, navbar, stats
23
+ status/ code, empty, error, loading
24
+ transforms/ Shared transforms
25
+ accordion, chart, codeflask, codemirror, comparison,
26
+ heatmap, interact, particles, sparkline, swiper, tabs, typed
17
27
 
18
28
  addons/ Built-in addon library
19
29
  core/
@@ -22,14 +32,14 @@ addons/ Built-in addon library
22
32
  clients/ HTTP + gRPC clients
23
33
  commands/ Typed API command system
24
34
  queue/ Concurrency task queue
35
+ assets/ Convention-based asset bundler (terser)
25
36
  render/
26
37
  directives/ ot-if, ot-for, ot-click, ot-fetch, ot-show, ot-html, ot-text
27
38
  pages/ SPA page router with CSS Grid layouts + async data loading
28
- elements/ 40+ pre-built UI components
29
- assets/ Convention-based asset bundler (terser)
39
+ elements/ UI component addon (registration, directives)
30
40
  html/ HTML document builder
31
41
  tags/ HTML tag system
32
- transforms/ Data transforms
42
+ transforms/ Transform addon (registration, loading, directives)
33
43
  modules/
34
44
  variables/ Named variable registry
35
45
  actions/ Action triggers
@@ -93,13 +103,16 @@ The framework uses Node.js package imports (`#` prefix) defined in `package.json
93
103
  "#database/*": "./addons/core/database/back/*",
94
104
  "#servers/*": "./addons/core/servers/back/*",
95
105
  "#clients/*": "./addons/core/clients/back/*",
96
- "#commands/*": "./addons/core/commands/back/*",
106
+ "#commands/*": "./addons/core/commands/*",
97
107
  "#queue/*": "./addons/core/queue/back/*",
98
- "#assets/*": "./addons/render/assets/back/*",
108
+ "#assets/*": "./addons/core/assets/back/*",
99
109
  "#html/*": "./addons/render/html/*",
100
110
  "#directives/*": "./addons/render/directives/*",
111
+ "#pages/*": "./addons/render/pages/*",
101
112
  "#elements/*": "./addons/render/elements/*",
102
- "#tags/*": "./addons/render/tags/*"
113
+ "#tags/*": "./addons/render/tags/*",
114
+ "#sources/*": "./addons/modules/sources/*",
115
+ "#variables/*": "./addons/modules/variables/*"
103
116
  }
104
117
  }
105
118
  ```
@@ -108,7 +121,7 @@ The framework uses Node.js package imports (`#` prefix) defined in `package.json
108
121
 
109
122
  ### Mixin composition over inheritance
110
123
 
111
- Both `OneType` and `OneTypeAddon` use `Object.assign(Class.prototype, mixin)`. No class hierarchies, no diamond problems. Each mixin is a plain object of methods that gets merged onto the prototype:
124
+ Both `OneType` and `OneTypeAddon` use `Object.assign(Class.prototype, mixin)`. No class hierarchies, no diamond problems. Each mixin is a plain object of methods merged onto the prototype:
112
125
 
113
126
  ```js
114
127
  import AddonItemGet from './mixins/get.js';
@@ -178,6 +191,41 @@ Receive:
178
191
 
179
192
  Transparent binary transport over the same stream.
180
193
 
194
+ ### Centralized asset registry
195
+
196
+ All asset paths are registered centrally in `lib/load.js` via `onetype.Assets(id, url, config)`. This decouples asset path knowledge from individual addons — the framework controls what gets bundled, regardless of whether a backend addon is loaded.
197
+
198
+ ```js
199
+ // lib/load.js — top-level registrations
200
+ onetype.Assets('framework', import.meta.url, { js: { path: '.', exclude: ['load.js', 'items', 'styles'] } });
201
+ onetype.Assets('styles', import.meta.url, { css: 'styles' });
202
+ onetype.Assets('commands', import.meta.url, { js: { path: '../addons/core/commands', exclude: ['../addons/core/commands/back'] } });
203
+ ```
204
+
205
+ Shared elements and transforms use `onetype.AddonReady` to register only after their parent addon is loaded. The JS files themselves contain the wrapper:
206
+
207
+ ```js
208
+ // lib/items/elements/form/button/button.js
209
+ onetype.AddonReady('elements', (elements) =>
210
+ {
211
+ elements.ItemAdd({ id: 'form-button', ... });
212
+ });
213
+
214
+ // lib/items/transforms/swiper/swiper.js
215
+ onetype.AddonReady('transforms', (transforms) =>
216
+ {
217
+ transforms.ItemAdd({ id: 'swiper', ... });
218
+ });
219
+ ```
220
+
221
+ Element IDs are group-prefixed: `form-button`, `global-card`, `sections-navbar`, `status-loading`. HTML tags follow the same pattern: `<e-form-button>`, `<e-global-card>`, `<e-status-loading>`.
222
+
223
+ The import function reads from the registry to resolve paths:
224
+
225
+ ```js
226
+ assets.Fn('import', ['framework', 'styles', 'commands', 'elements/form/input', 'transforms/swiper']);
227
+ ```
228
+
181
229
  ### Convention-based bundling
182
230
 
183
231
  No webpack, no build configuration. The asset bundler:
package/docs/frontend.md CHANGED
@@ -330,22 +330,39 @@ Usage:
330
330
 
331
331
  Convention-based bundler that scans directories, strips ES module syntax, concatenates, and minifies.
332
332
 
333
+ ### Asset registry
334
+
335
+ All asset paths are registered centrally in `lib/load.js` via `onetype.Assets()`. The import function resolves IDs to paths from this registry.
336
+
333
337
  ```js
334
- import assets from '#assets/load.js';
338
+ // In application back/index.js — import by ID
339
+ assets.Fn('import', ['framework', 'styles', 'commands', 'elements/input', 'transforms/swiper']);
340
+ ```
335
341
 
336
- // Scan directories in order
337
- assets.Item({ type: 'js', order: 0, path: 'framework' });
338
- assets.Item({ type: 'js', order: 1, path: 'addons/core/commands/front' });
339
- assets.Item({ type: 'js', order: 1, path: 'addons/render/directives/front' });
340
- assets.Item({ type: 'js', order: 1, path: 'addons/render/pages/front' });
342
+ Available asset IDs:
341
343
 
342
- // CSS
343
- assets.Item({ type: 'css', order: 0, path: 'styles' });
344
- assets.Item({ type: 'css', order: 1, path: 'addons/render/elements/front' });
345
- assets.Item({ type: 'css', order: 2, path: 'projects/travel/site/front' });
344
+ | ID | Type | Description |
345
+ |---|---|---|
346
+ | `framework` | js | Core framework library |
347
+ | `styles` | css | Shared CSS (variables, reset, queries, utilities) |
348
+ | `commands` | js | Command system (front-end) |
349
+ | `database` | js | Database (front-end) |
350
+ | `directives` | js | Directives addon |
351
+ | `transforms` | js | Transforms addon |
352
+ | `pages` | js+css | Page router addon |
353
+ | `elements` | js+css | Elements addon |
354
+ | `float` | js+css | Float system (modals, toasts, tooltips, popups, overlays) |
355
+ | `elements/form/input` | js+css | Granular element import |
356
+ | `transforms/swiper` | js | Granular transform import |
346
357
 
347
- // Ignore specific files
348
- assets.Item({ type: 'js', order: 0, path: 'framework', ignore: ['framework/load.js'] });
358
+ Granular imports use `elements/<group>/<name>` and `transforms/<name>` format. Element groups: `form`, `global`, `sections`, `status`.
359
+
360
+ ### Manual asset items
361
+
362
+ ```js
363
+ // Scan a custom directory
364
+ assets.Item({ type: 'js', order: 2, path: resolve(root, 'front') });
365
+ assets.Item({ type: 'css', order: 2, path: resolve(root, 'front') });
349
366
  ```
350
367
 
351
368
  ### Dynamic content injection
@@ -0,0 +1,106 @@
1
+ onetype.AddonReady('elements', (elements) =>
2
+ {
3
+ elements.ItemAdd({
4
+ id: 'form-button',
5
+ icon: 'smart_button',
6
+ name: 'Button',
7
+ description: 'Premium button with icons, variants, animations, and ripple effects.',
8
+ category: 'Form',
9
+ author: 'OneType',
10
+ example: [
11
+ { title: 'Solid', code: '<e-button text="Brand" icon="add"></e-button>' },
12
+ { title: 'Soft', code: '<e-button text="Soft" icon="cloud" :variant="[\'soft-brand\']"></e-button>' },
13
+ { title: 'Outline', code: '<e-button text="Outline" icon="edit" :variant="[\'outline-brand\']"></e-button>' },
14
+ { title: 'Border', code: '<e-button text="Border" :variant="[\'border\']"></e-button>' },
15
+ { title: 'Ghost', code: '<e-button text="Ghost" :variant="[\'ghost\']"></e-button>' },
16
+ { title: 'Icon Only', code: '<e-button icon="add" :variant="[\'icon-only\']"></e-button>' }
17
+ ],
18
+ config: {
19
+ icon: {
20
+ type: 'string',
21
+ },
22
+ iconRight: {
23
+ type: 'string',
24
+ },
25
+ text: {
26
+ type: 'string',
27
+ value: 'Button'
28
+ },
29
+ href: {
30
+ type: 'string',
31
+ },
32
+ target: {
33
+ type: 'string',
34
+ options: ['_blank', '_self', '_parent', '_top']
35
+ },
36
+ type: {
37
+ type: 'string',
38
+ value: 'button',
39
+ options: ['button', 'submit', 'reset']
40
+ },
41
+ disabled: {
42
+ type: 'boolean',
43
+ value: false
44
+ },
45
+ loading: {
46
+ type: 'boolean',
47
+ value: false
48
+ },
49
+ variant: {
50
+ type: 'array',
51
+ value: ['brand', 'size-m'],
52
+ options: [
53
+ 'brand', 'blue', 'red', 'orange', 'green',
54
+ 'soft-brand', 'soft-blue', 'soft-red', 'soft-orange', 'soft-green',
55
+ 'outline-brand', 'outline-blue', 'outline-red', 'outline-orange', 'outline-green',
56
+ 'bg-1', 'bg-2', 'bg-3', 'bg-4',
57
+ 'ghost', 'glass', 'border', 'transparent',
58
+ 'size-s', 'size-m', 'size-l',
59
+ 'full', 'icon-only', 'rounded'
60
+ ]
61
+ },
62
+ _click: {
63
+ type: 'function'
64
+ }
65
+ },
66
+ render: function()
67
+ {
68
+ this.handleClick = (e) =>
69
+ {
70
+ if(this.disabled || this.loading)
71
+ {
72
+ return;
73
+ }
74
+
75
+ if(this._click)
76
+ {
77
+ this._click(e);
78
+ }
79
+ };
80
+
81
+ const content = `
82
+ <span ot-if="loading" class="spinner"><i>progress_activity</i></span>
83
+ <span ot-if="!loading" class="content">
84
+ <i ot-if="icon" class="icon-left">{{ icon }}</i>
85
+ <span ot-if="text && !variant.includes('icon-only')" class="text">{{ text }}</span>
86
+ <i ot-if="iconRight" class="icon-right">{{ iconRight }}</i>
87
+ </span>
88
+ `;
89
+
90
+ if(this.href)
91
+ {
92
+ return `
93
+ <a class="holder" :href="href" :target="target" :variant="variant.join(' ')" :disabled="disabled" :loading="loading" ot-click="handleClick">
94
+ ${content}
95
+ </a>
96
+ `;
97
+ }
98
+
99
+ return `
100
+ <button class="holder" :type="type" :variant="variant.join(' ')" :disabled="disabled" :loading="loading" ot-click="handleClick">
101
+ ${content}
102
+ </button>
103
+ `;
104
+ }
105
+ });
106
+ });
@@ -0,0 +1,176 @@
1
+ .e-64e877b
2
+ {
3
+ display: flex;
4
+ }
5
+
6
+ /* Button Base */
7
+ .e-64e877b > .holder
8
+ {
9
+ position: relative;
10
+ border: 1px solid transparent;
11
+ border-radius: var(--ot-radius-m);
12
+ padding: 4px var(--ot-spacing-m);
13
+ cursor: pointer;
14
+ outline: none;
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ gap: var(--ot-spacing-s);
19
+ background: transparent;
20
+ color: var(--ot-text-1);
21
+ font-size: var(--ot-size-m);
22
+ font-weight: 500;
23
+ text-decoration: none;
24
+ white-space: nowrap;
25
+ overflow: hidden;
26
+ user-select: none;
27
+
28
+ -webkit-tap-highlight-color: transparent;
29
+ transition:
30
+ background 0.2s ease,
31
+ border-color 0.2s ease,
32
+ color 0.2s ease,
33
+ box-shadow 0.2s ease,
34
+ transform 0.15s ease;
35
+ }
36
+
37
+ /* Content wrapper */
38
+ .e-64e877b > .holder > .content
39
+ {
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ gap: var(--ot-spacing-s);
44
+ transition: transform 0.2s ease;
45
+ }
46
+
47
+ /* Text */
48
+ .e-64e877b > .holder > .content > .text
49
+ {
50
+ line-height: 1;
51
+ }
52
+
53
+ /* Icons */
54
+ .e-64e877b > .holder > .content > i
55
+ {
56
+ font-size: 18px;
57
+ transition: transform 0.2s ease;
58
+ }
59
+
60
+ .e-64e877b > .holder > .content > .icon-left
61
+ {
62
+ margin-right: -2px;
63
+ }
64
+
65
+ .e-64e877b > .holder > .content > .icon-right
66
+ {
67
+ margin-left: -2px;
68
+ }
69
+
70
+ /* Hover - subtle lift */
71
+ .e-64e877b > .holder:hover
72
+ {
73
+ transform: translateY(-1px);
74
+ }
75
+
76
+ .e-64e877b > .holder:hover > .content > .icon-right
77
+ {
78
+ transform: translateX(2px);
79
+ }
80
+
81
+ /* Active - press down */
82
+ .e-64e877b > .holder:active
83
+ {
84
+ transform: translateY(0) scale(0.98);
85
+ transition-duration: 0.1s;
86
+ }
87
+
88
+ /* Focus visible - premium glow ring */
89
+ .e-64e877b > .holder:focus-visible
90
+ {
91
+ outline: none;
92
+ box-shadow:
93
+ 0 0 0 2px var(--ot-bg-1),
94
+ 0 0 0 4px var(--ot-brand);
95
+ }
96
+
97
+ /* Disabled */
98
+ .e-64e877b > .holder[disabled="true"]
99
+ {
100
+ opacity: 0.5;
101
+ cursor: not-allowed;
102
+ pointer-events: none;
103
+ transform: none;
104
+ }
105
+
106
+ /* Loading */
107
+ .e-64e877b > .holder[loading="true"]
108
+ {
109
+ cursor: wait;
110
+ pointer-events: none;
111
+ }
112
+
113
+ /* Spinner */
114
+ .e-64e877b > .holder > .spinner
115
+ {
116
+ display: inline-flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ }
120
+
121
+ .e-64e877b > .holder > .spinner > i
122
+ {
123
+ font-size: 18px;
124
+ animation: e-button-spin 0.8s linear infinite;
125
+ }
126
+
127
+ @keyframes e-button-spin
128
+ {
129
+ from { transform: rotate(0deg); }
130
+ to { transform: rotate(360deg); }
131
+ }
132
+
133
+ /* Ripple effect */
134
+ .e-64e877b > .holder > .ripple
135
+ {
136
+ position: absolute;
137
+ border-radius: 50%;
138
+ background: currentColor;
139
+ opacity: 0.15;
140
+ transform: scale(0);
141
+ animation: e-button-ripple 0.6s ease-out forwards;
142
+ pointer-events: none;
143
+ }
144
+
145
+ @keyframes e-button-ripple
146
+ {
147
+ to
148
+ {
149
+ transform: scale(2.5);
150
+ opacity: 0;
151
+ }
152
+ }
153
+
154
+ /* Full width */
155
+ .e-64e877b > .holder[variant*="full"]
156
+ {
157
+ width: 100%;
158
+ }
159
+
160
+ /* Rounded (pill) */
161
+ .e-64e877b > .holder[variant*="rounded"]
162
+ {
163
+ border-radius: 100px;
164
+ }
165
+
166
+ /* Icon only - square aspect */
167
+ .e-64e877b > .holder[variant*="icon-only"]
168
+ {
169
+ padding: 0;
170
+ aspect-ratio: 1;
171
+ }
172
+
173
+ .e-64e877b > .holder[variant*="icon-only"] > .content > i
174
+ {
175
+ margin: 0;
176
+ }
@@ -0,0 +1,78 @@
1
+ /* Small */
2
+ .e-64e877b > .holder[variant*="size-s"]
3
+ {
4
+ height: var(--ot-height-s);
5
+ padding: 0 var(--ot-spacing-s);
6
+ font-size: var(--ot-size-s);
7
+ gap: var(--ot-spacing-x);
8
+ }
9
+
10
+ .e-64e877b > .holder[variant*="size-s"] > .content
11
+ {
12
+ gap: var(--ot-spacing-x);
13
+ }
14
+
15
+ .e-64e877b > .holder[variant*="size-s"] > .content > i,
16
+ .e-64e877b > .holder[variant*="size-s"] > .spinner > i
17
+ {
18
+ font-size: 14px;
19
+ }
20
+
21
+ /* Medium (default) */
22
+ .e-64e877b > .holder[variant*="size-m"]
23
+ {
24
+ height: var(--ot-height-m);
25
+ padding: 0 var(--ot-spacing-m);
26
+ font-size: var(--ot-size-m);
27
+ gap: var(--ot-spacing-s);
28
+ }
29
+
30
+ .e-64e877b > .holder[variant*="size-m"] > .content
31
+ {
32
+ gap: var(--ot-spacing-s);
33
+ }
34
+
35
+ .e-64e877b > .holder[variant*="size-m"] > .content > i,
36
+ .e-64e877b > .holder[variant*="size-m"] > .spinner > i
37
+ {
38
+ font-size: 18px;
39
+ }
40
+
41
+ /* Large */
42
+ .e-64e877b > .holder[variant*="size-l"]
43
+ {
44
+ height: var(--ot-height-l);
45
+ padding: 0 var(--ot-spacing-l);
46
+ font-size: var(--ot-size-l);
47
+ gap: var(--ot-spacing-m);
48
+ }
49
+
50
+ .e-64e877b > .holder[variant*="size-l"] > .content
51
+ {
52
+ gap: var(--ot-spacing-m);
53
+ }
54
+
55
+ .e-64e877b > .holder[variant*="size-l"] > .content > i,
56
+ .e-64e877b > .holder[variant*="size-l"] > .spinner > i
57
+ {
58
+ font-size: 22px;
59
+ }
60
+
61
+ /* Icon-only size adjustments */
62
+ .e-64e877b > .holder[variant*="icon-only"][variant*="size-s"]
63
+ {
64
+ width: var(--ot-height-s);
65
+ padding: 0;
66
+ }
67
+
68
+ .e-64e877b > .holder[variant*="icon-only"][variant*="size-m"]
69
+ {
70
+ width: var(--ot-height-m);
71
+ padding: 0;
72
+ }
73
+
74
+ .e-64e877b > .holder[variant*="icon-only"][variant*="size-l"]
75
+ {
76
+ width: var(--ot-height-l);
77
+ padding: 0;
78
+ }