tosijs-ui 1.0.0

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 (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/ab-test.d.ts +14 -0
  4. package/dist/ab-test.js +116 -0
  5. package/dist/babylon-3d.d.ts +53 -0
  6. package/dist/babylon-3d.js +292 -0
  7. package/dist/bodymovin-player.d.ts +32 -0
  8. package/dist/bodymovin-player.js +172 -0
  9. package/dist/bp-loader.d.ts +1 -0
  10. package/dist/bp-loader.js +26 -0
  11. package/dist/carousel.d.ts +113 -0
  12. package/dist/carousel.js +308 -0
  13. package/dist/code-editor.d.ts +27 -0
  14. package/dist/code-editor.js +102 -0
  15. package/dist/color-input.d.ts +41 -0
  16. package/dist/color-input.js +112 -0
  17. package/dist/data-table.d.ts +79 -0
  18. package/dist/data-table.js +774 -0
  19. package/dist/drag-and-drop.d.ts +2 -0
  20. package/dist/drag-and-drop.js +386 -0
  21. package/dist/editable-rect.d.ts +97 -0
  22. package/dist/editable-rect.js +450 -0
  23. package/dist/filter-builder.d.ts +64 -0
  24. package/dist/filter-builder.js +468 -0
  25. package/dist/float.d.ts +18 -0
  26. package/dist/float.js +170 -0
  27. package/dist/form.d.ts +68 -0
  28. package/dist/form.js +466 -0
  29. package/dist/gamepad.d.ts +34 -0
  30. package/dist/gamepad.js +115 -0
  31. package/dist/icon-data.d.ts +312 -0
  32. package/dist/icon-data.js +308 -0
  33. package/dist/icon-types.d.ts +7 -0
  34. package/dist/icon-types.js +1 -0
  35. package/dist/icons.d.ts +17 -0
  36. package/dist/icons.js +374 -0
  37. package/dist/iife.js +69 -0
  38. package/dist/iife.js.map +49 -0
  39. package/dist/index-iife.d.ts +1 -0
  40. package/dist/index-iife.js +4 -0
  41. package/dist/index.d.ts +37 -0
  42. package/dist/index.js +37 -0
  43. package/dist/index.js.map +47 -0
  44. package/dist/live-example.d.ts +63 -0
  45. package/dist/live-example.js +611 -0
  46. package/dist/localize.d.ts +46 -0
  47. package/dist/localize.js +381 -0
  48. package/dist/make-sorter.d.ts +3 -0
  49. package/dist/make-sorter.js +119 -0
  50. package/dist/make-sorter.test.d.ts +1 -0
  51. package/dist/make-sorter.test.js +48 -0
  52. package/dist/mapbox.d.ts +24 -0
  53. package/dist/mapbox.js +161 -0
  54. package/dist/markdown-viewer.d.ts +17 -0
  55. package/dist/markdown-viewer.js +173 -0
  56. package/dist/match-shortcut.d.ts +9 -0
  57. package/dist/match-shortcut.js +13 -0
  58. package/dist/match-shortcut.test.d.ts +1 -0
  59. package/dist/match-shortcut.test.js +194 -0
  60. package/dist/menu.d.ts +60 -0
  61. package/dist/menu.js +614 -0
  62. package/dist/notifications.d.ts +106 -0
  63. package/dist/notifications.js +308 -0
  64. package/dist/password-strength.d.ts +35 -0
  65. package/dist/password-strength.js +302 -0
  66. package/dist/playwright.config.d.ts +9 -0
  67. package/dist/playwright.config.js +73 -0
  68. package/dist/pop-float.d.ts +10 -0
  69. package/dist/pop-float.js +231 -0
  70. package/dist/rating.d.ts +62 -0
  71. package/dist/rating.js +192 -0
  72. package/dist/rich-text.d.ts +35 -0
  73. package/dist/rich-text.js +296 -0
  74. package/dist/segmented.d.ts +80 -0
  75. package/dist/segmented.js +298 -0
  76. package/dist/select.d.ts +43 -0
  77. package/dist/select.js +427 -0
  78. package/dist/side-nav.d.ts +36 -0
  79. package/dist/side-nav.js +106 -0
  80. package/dist/size-break.d.ts +18 -0
  81. package/dist/size-break.js +118 -0
  82. package/dist/sizer.d.ts +34 -0
  83. package/dist/sizer.js +92 -0
  84. package/dist/src/ab-test.d.ts +14 -0
  85. package/dist/src/babylon-3d.d.ts +53 -0
  86. package/dist/src/bodymovin-player.d.ts +32 -0
  87. package/dist/src/bp-loader.d.ts +0 -0
  88. package/dist/src/carousel.d.ts +113 -0
  89. package/dist/src/code-editor.d.ts +27 -0
  90. package/dist/src/color-input.d.ts +41 -0
  91. package/dist/src/data-table.d.ts +79 -0
  92. package/dist/src/drag-and-drop.d.ts +2 -0
  93. package/dist/src/editable-rect.d.ts +97 -0
  94. package/dist/src/filter-builder.d.ts +64 -0
  95. package/dist/src/float.d.ts +18 -0
  96. package/dist/src/form.d.ts +68 -0
  97. package/dist/src/gamepad.d.ts +34 -0
  98. package/dist/src/icon-data.d.ts +309 -0
  99. package/dist/src/icon-types.d.ts +7 -0
  100. package/dist/src/icons.d.ts +17 -0
  101. package/dist/src/index.d.ts +37 -0
  102. package/dist/src/live-example.d.ts +51 -0
  103. package/dist/src/localize.d.ts +30 -0
  104. package/dist/src/make-sorter.d.ts +3 -0
  105. package/dist/src/mapbox.d.ts +24 -0
  106. package/dist/src/markdown-viewer.d.ts +15 -0
  107. package/dist/src/match-shortcut.d.ts +9 -0
  108. package/dist/src/menu.d.ts +60 -0
  109. package/dist/src/notifications.d.ts +106 -0
  110. package/dist/src/password-strength.d.ts +35 -0
  111. package/dist/src/pop-float.d.ts +10 -0
  112. package/dist/src/rating.d.ts +62 -0
  113. package/dist/src/rich-text.d.ts +28 -0
  114. package/dist/src/segmented.d.ts +80 -0
  115. package/dist/src/select.d.ts +43 -0
  116. package/dist/src/side-nav.d.ts +36 -0
  117. package/dist/src/size-break.d.ts +18 -0
  118. package/dist/src/sizer.d.ts +34 -0
  119. package/dist/src/tab-selector.d.ts +91 -0
  120. package/dist/src/tag-list.d.ts +37 -0
  121. package/dist/src/track-drag.d.ts +5 -0
  122. package/dist/src/version.d.ts +1 -0
  123. package/dist/src/via-tag.d.ts +2 -0
  124. package/dist/tab-selector.d.ts +91 -0
  125. package/dist/tab-selector.js +326 -0
  126. package/dist/tag-list.d.ts +37 -0
  127. package/dist/tag-list.js +375 -0
  128. package/dist/track-drag.d.ts +5 -0
  129. package/dist/track-drag.js +143 -0
  130. package/dist/version.d.ts +1 -0
  131. package/dist/version.js +1 -0
  132. package/dist/via-tag.d.ts +2 -0
  133. package/dist/via-tag.js +102 -0
  134. package/package.json +58 -0
@@ -0,0 +1,73 @@
1
+ import { defineConfig, devices } from '@playwright/test';
2
+ /**
3
+ * Read environment variables from file.
4
+ * https://github.com/motdotla/dotenv
5
+ */
6
+ // import dotenv from 'dotenv';
7
+ // dotenv.config({ path: path.resolve(__dirname, '.env') });
8
+ /**
9
+ * See https://playwright.dev/docs/test-configuration.
10
+ */
11
+ export default defineConfig({
12
+ testDir: './tests',
13
+ /* Run tests in files in parallel */
14
+ fullyParallel: true,
15
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
16
+ forbidOnly: !!process.env.CI,
17
+ /* Retry on CI only */
18
+ retries: process.env.CI ? 2 : 0,
19
+ /* Opt out of parallel tests on CI. */
20
+ workers: process.env.CI ? 1 : undefined,
21
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
22
+ reporter: 'html',
23
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
24
+ /* use .pw.ts for playwright (vs. bun) tests */
25
+ testMatch: /.*\.pw\.ts/,
26
+ use: {
27
+ /* Base URL to use in actions like `await page.goto('/')`. */
28
+ // baseURL: 'http://127.0.0.1:3000',
29
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30
+ trace: 'on-first-retry',
31
+ /* allow https on localhost with self-signed certificate */
32
+ ignoreHTTPSErrors: true,
33
+ },
34
+ /* Configure projects for major browsers */
35
+ projects: [
36
+ {
37
+ name: 'chromium',
38
+ use: { ...devices['Desktop Chrome'] },
39
+ },
40
+ {
41
+ name: 'firefox',
42
+ use: { ...devices['Desktop Firefox'] },
43
+ },
44
+ {
45
+ name: 'webkit',
46
+ use: { ...devices['Desktop Safari'] },
47
+ },
48
+ /* Test against mobile viewports. */
49
+ // {
50
+ // name: 'Mobile Chrome',
51
+ // use: { ...devices['Pixel 5'] },
52
+ // },
53
+ // {
54
+ // name: 'Mobile Safari',
55
+ // use: { ...devices['iPhone 12'] },
56
+ // },
57
+ /* Test against branded browsers. */
58
+ // {
59
+ // name: 'Microsoft Edge',
60
+ // use: { ...devices['Desktop Edge'], channel: 'msedge' },
61
+ // },
62
+ // {
63
+ // name: 'Google Chrome',
64
+ // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
65
+ // },
66
+ ],
67
+ /* Run your local dev server before starting the tests */
68
+ // webServer: {
69
+ // command: 'npm run start',
70
+ // url: 'http://127.0.0.1:3000',
71
+ // reuseExistingServer: !process.env.CI,
72
+ // },
73
+ });
@@ -0,0 +1,10 @@
1
+ import { ElementPart } from 'tosijs';
2
+ import { XinFloat } from './float';
3
+ export type FloatPosition = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'en' | 'wn' | 'es' | 'ws' | 'side' | 'auto';
4
+ export interface PopFloatOptions {
5
+ content: HTMLElement | ElementPart[];
6
+ target: HTMLElement;
7
+ position?: FloatPosition;
8
+ }
9
+ export declare const popFloat: (options: PopFloatOptions) => XinFloat;
10
+ export declare const positionFloat: (element: HTMLElement, target: HTMLElement, position?: FloatPosition) => void;
@@ -0,0 +1,231 @@
1
+ /*#
2
+ # popFloat
3
+
4
+ There are so many cases in user-interfaces where it's useful to pop-up a floating
5
+ user interface element that a simple and reliable way of doing this seems like
6
+ a good idea.
7
+
8
+ The problem with many such approaches is that they assume a highly specific
9
+ use-case (e.g. popup menu or combo box) and while meeting the creator's intended
10
+ purpose admirably, turn out to have some annoying limitation that prevents them
11
+ handling the specific case at hand.
12
+
13
+ ```js
14
+ const { popFloat, positionFloat } = xinjsui
15
+ const { button } = xinjs.elements
16
+ const grid = preview.querySelector('.grid')
17
+
18
+ grid.addEventListener('click', (event) => {
19
+ const { target } = event
20
+ if (!target.closest('button')) {
21
+ return
22
+ }
23
+ const float = preview.querySelector('xin-float')
24
+ if (float === null) {
25
+ // create and position a float
26
+ preview.append(
27
+ popFloat({
28
+ content: [
29
+ 'hello, I am a float',
30
+ button('close me', {
31
+ onClick(event){
32
+ event.target.closest('xin-float').remove()
33
+ }
34
+ })
35
+ ],
36
+ target,
37
+ position: target.dataset.float
38
+ })
39
+ )
40
+ } else {
41
+ // position an existing float
42
+ positionFloat(float, target, target.dataset.float)
43
+ }
44
+ })
45
+ ```
46
+ ```html
47
+ <h2>Pop Float Demo</h2>
48
+ <div class="grid">
49
+ <button data-float="nw">nw</button>
50
+ <button data-float="n">n</button>
51
+ <button data-float="ne">ne</button>
52
+ <button data-float="wn">wn</button>
53
+ <span>&nbsp;</span>
54
+ <button data-float="en">en</button>
55
+ <button data-float="w">w</button>
56
+ <button data-float="auto">auto</button>
57
+ <button data-float="e">e</button>
58
+ <button data-float="ws">ws</button>
59
+ <button data-float="side">side</button>
60
+ <button data-float="es">es</button>
61
+ <button data-float="sw">sw</button>
62
+ <button data-float="s">s</button>
63
+ <button data-float="se">se</button>
64
+ </div>
65
+ ```
66
+ ```css
67
+ .preview .grid {
68
+ display: grid;
69
+ grid-template-columns: 80px 80px 80px;
70
+ }
71
+
72
+ .preview xin-float {
73
+ display: flex;
74
+ flex-direction: column;
75
+ border-radius: 5px;
76
+ padding: 10px;
77
+ background: white;
78
+ box-shadow: 2px 10px 5px #0004;
79
+ }
80
+ ```
81
+
82
+ ## popFloat
83
+
84
+ ```
85
+ export interface PopFloatOptions {
86
+ content: HTMLElement | ElementPart[]
87
+ target: HTMLElement
88
+ position?: FloatPosition
89
+ }
90
+
91
+ export const popFloat = (options: PopFloatOptions): XinFloat
92
+ ```
93
+
94
+ Create a `<xin-float>` with the content provided, positioned as specified (or automatically).
95
+
96
+ ## positionFloat
97
+
98
+ ```
99
+ export const positionFloat = (
100
+ element: HTMLElement,
101
+ target: HTMLElement,
102
+ position?: FloatPosition
103
+ remainOnScroll?: 'hide' | 'remove' | boolean // default is 'remove'
104
+ remainOnResize?: 'hide' | 'remove' | boolean // default is 'remove'
105
+ ): void
106
+ ```
107
+
108
+ This allows you to, for example, provide a global menu that can be used on any element
109
+ instead of needing to have a whole instance of the menu wrapped around every instance
110
+ of the thing you want the menu to affect (a common anti-pattern of front-end frameworks).
111
+
112
+ ### Handling Overflow
113
+
114
+ `positionFloat` automatically sets two css-variables `--max-height` and `--max-width` on
115
+ the floating element to help you deal with overflow (e.g. in menus). E.g. if the float
116
+ is positioned with `top: 125px` then it will set `--max-height: calc(100vh - 125px)`.
117
+
118
+ ## FloatPosition
119
+
120
+ ```
121
+ export type FloatPosition =
122
+ | 'n'
123
+ | 's'
124
+ | 'e'
125
+ | 'w'
126
+ | 'ne'
127
+ | 'nw'
128
+ | 'se'
129
+ | 'sw'
130
+ | 'en'
131
+ | 'wn'
132
+ | 'es'
133
+ | 'ws'
134
+ | 'side'
135
+ | 'auto'
136
+ ```
137
+
138
+ */
139
+ import { xinFloat } from './float';
140
+ import { bringToFront } from './track-drag';
141
+ export const popFloat = (options) => {
142
+ const { content, target, position } = options;
143
+ const float = Array.isArray(content)
144
+ ? xinFloat(...content)
145
+ : xinFloat(content);
146
+ positionFloat(float, target, position);
147
+ document.body.append(float);
148
+ return float;
149
+ };
150
+ export const positionFloat = (element, target, position) => {
151
+ {
152
+ const { position } = getComputedStyle(element);
153
+ if (position !== 'fixed') {
154
+ element.style.position = 'fixed';
155
+ }
156
+ bringToFront(element);
157
+ }
158
+ const { left, top, width, height } = target.getBoundingClientRect();
159
+ const cx = left + width * 0.5;
160
+ const cy = top + height * 0.5;
161
+ const w = window.innerWidth;
162
+ const h = window.innerHeight;
163
+ if (position === 'side') {
164
+ position = ((cx < w * 0.5 ? 'e' : 'w') +
165
+ (cy < h * 0.5 ? 's' : 'n'));
166
+ }
167
+ else if (position === 'auto' || position === undefined) {
168
+ position = ((cy < h * 0.5 ? 's' : 'n') +
169
+ (cx < w * 0.5 ? 'e' : 'w'));
170
+ }
171
+ element.style.top =
172
+ element.style.left =
173
+ element.style.right =
174
+ element.style.bottom =
175
+ element.style.transform =
176
+ '';
177
+ if (position.length === 2) {
178
+ const [first, second] = position;
179
+ switch (first) {
180
+ case 'n':
181
+ element.style.bottom = (h - top).toFixed(2) + 'px';
182
+ break;
183
+ case 'e':
184
+ element.style.left = (left + width).toFixed(2) + 'px';
185
+ break;
186
+ case 's':
187
+ element.style.top = (top + height).toFixed(2) + 'px';
188
+ break;
189
+ case 'w':
190
+ element.style.right = (w - left).toFixed(2) + 'px';
191
+ break;
192
+ }
193
+ switch (second) {
194
+ case 'n':
195
+ element.style.bottom = (h - top - height).toFixed(2) + 'px';
196
+ break;
197
+ case 'e':
198
+ element.style.left = left.toFixed(2) + 'px';
199
+ break;
200
+ case 's':
201
+ element.style.top = top.toFixed(2) + 'px';
202
+ break;
203
+ case 'w':
204
+ element.style.right = (w - left - width).toFixed(2) + 'px';
205
+ break;
206
+ }
207
+ element.style.transform = '';
208
+ }
209
+ else if (position === 'n') {
210
+ element.style.bottom = (h - top).toFixed(2) + 'px';
211
+ element.style.left = cx.toFixed(2) + 'px';
212
+ element.style.transform = 'translateX(-50%)';
213
+ }
214
+ else if (position === 's') {
215
+ element.style.top = (top + height).toFixed(2) + 'px';
216
+ element.style.left = cx.toFixed(2) + 'px';
217
+ element.style.transform = 'translateX(-50%)';
218
+ }
219
+ else if (position === 'e') {
220
+ element.style.left = (left + width).toFixed(2) + 'px';
221
+ element.style.top = cy.toFixed(2) + 'px';
222
+ element.style.transform = 'translateY(-50%)';
223
+ }
224
+ else if (position === 'w') {
225
+ element.style.right = (w - left).toFixed(2) + 'px';
226
+ element.style.top = cy.toFixed(2) + 'px';
227
+ element.style.transform = 'translateY(-50%)';
228
+ }
229
+ element.style.setProperty('--max-height', `calc(100vh - ${element.style.top || element.style.bottom})`);
230
+ element.style.setProperty('--max-width', `calc(100vw - ${element.style.left || element.style.right})`);
231
+ };
@@ -0,0 +1,62 @@
1
+ import { Component, ElementCreator } from 'tosijs';
2
+ export declare class XinRating extends Component {
3
+ iconSize: number;
4
+ min: 0 | 1;
5
+ max: number;
6
+ step: number;
7
+ value: number | null;
8
+ icon: string;
9
+ ratingFill: string;
10
+ ratingStroke: string;
11
+ emptyFill: string;
12
+ emptyStroke: string;
13
+ readonly: boolean;
14
+ hollow: boolean;
15
+ static styleSpec: {
16
+ ':host': {
17
+ display: string;
18
+ position: string;
19
+ width: string;
20
+ };
21
+ ':host::part(container)': {
22
+ position: string;
23
+ display: string;
24
+ };
25
+ ':host::part(empty), :host::part(filled)': {
26
+ height: string;
27
+ whiteSpace: string;
28
+ overflow: string;
29
+ };
30
+ ':host::part(empty)': {
31
+ pointerEvents: string;
32
+ _xinIconFill: string;
33
+ _xinIconStroke: string;
34
+ };
35
+ ':host::part(filled)': {
36
+ position: string;
37
+ left: number;
38
+ _xinIconFill: string;
39
+ _xinIconStroke: string;
40
+ };
41
+ ':host svg': {
42
+ transform: string;
43
+ pointerEvents: string;
44
+ transition: string;
45
+ };
46
+ ':host svg:hover': {
47
+ transform: string;
48
+ };
49
+ ':host svg:active': {
50
+ transform: string;
51
+ };
52
+ };
53
+ constructor();
54
+ content: () => HTMLSpanElement;
55
+ displayValue(value: number | null): void;
56
+ update: (event: Event) => void;
57
+ handleKey: (event: KeyboardEvent) => void;
58
+ connectedCallback(): void;
59
+ private _renderedIcon;
60
+ render(): void;
61
+ }
62
+ export declare const xinRating: ElementCreator<XinRating>;
package/dist/rating.js ADDED
@@ -0,0 +1,192 @@
1
+ /*#
2
+ # rating
3
+
4
+ `XinRating` / `<xin-rating>` provides a drop-in replacement for an `<input>`
5
+ that renders a rating using <xin-icon icon="star" color="red"></xin-icon>s.
6
+
7
+ ```html
8
+ <xin-rating value=3.4></xin-rating>
9
+ <xin-rating min=0 value=3.4 step=0.5 hollow></xin-rating>
10
+ <xin-rating value=3.4 color="deepskyblue"></xin-rating>
11
+ <xin-rating value=3.1 max=10 color="hotpink" icon="heart" icon-size=32></xin-rating>
12
+ ```
13
+ ```css
14
+ .preview {
15
+ display: flex;
16
+ flex-direction: column;
17
+ }
18
+ ```
19
+
20
+ ## Attributes
21
+
22
+ - `icon-size` (24 by default) determines the height of the control and along with `max` its width
23
+ - `max` maximum rating
24
+ - `min` (1 by default) can be 0 or 1 (allowing ratings of 0 to max or 1 to max)
25
+ - `step` (0.5 by default) granularity of rating
26
+ - `icon` ('star' by default) determines the icon used
27
+ - `rating-stroke` (#f91 by default) is the stroke of rating icons
28
+ - `rating-fill` (#e81 by default) is the color of rating icons
29
+ - `empty-stroke` (none by default) is the color of background icons
30
+ - `empty-fill` (#ccc by default) is the color of background icons
31
+ - `readonly` (false by default) prevents the user from changing the rating
32
+ - `hollow` (false by default) makes the empty rating icons hollow.
33
+
34
+ ## Keyboard
35
+
36
+ `<xin-rating>` should be fully keyboard navigable (and, I hope, accessible).
37
+
38
+ The up key increases the rating, down descreases it. This is the same
39
+ as the behavior of `<input type="number">`, [Shoelace's rating widget](https://shoelace.style/components/rating/),
40
+ and (in my opinion) common sense, but not like [MUI's rating widget](https://mui.com/material-ui/react-rating/).
41
+ */
42
+ import { Component, elements, vars } from 'xinjs';
43
+ import { icons } from './icons';
44
+ const { span } = elements;
45
+ export class XinRating extends Component {
46
+ iconSize = 24;
47
+ min = 1;
48
+ max = 5;
49
+ step = 1;
50
+ value = null;
51
+ icon = 'star';
52
+ ratingFill = '#f91';
53
+ ratingStroke = '#e81';
54
+ emptyFill = '#ccc';
55
+ emptyStroke = 'none';
56
+ readonly = false;
57
+ hollow = false;
58
+ static styleSpec = {
59
+ ':host': {
60
+ display: 'inline-block',
61
+ position: 'relative',
62
+ width: 'fit-content',
63
+ },
64
+ ':host::part(container)': {
65
+ position: 'relative',
66
+ display: 'inline-block',
67
+ },
68
+ ':host::part(empty), :host::part(filled)': {
69
+ height: '100%',
70
+ whiteSpace: 'nowrap',
71
+ overflow: 'hidden',
72
+ },
73
+ ':host::part(empty)': {
74
+ pointerEvents: 'none',
75
+ _xinIconFill: vars.emptyFill,
76
+ _xinIconStroke: vars.emptyStroke,
77
+ },
78
+ ':host::part(filled)': {
79
+ position: 'absolute',
80
+ left: 0,
81
+ _xinIconFill: vars.ratingFill,
82
+ _xinIconStroke: vars.ratingStroke,
83
+ },
84
+ ':host svg': {
85
+ transform: 'scale(0.9)',
86
+ pointerEvents: 'all !important',
87
+ transition: '0.25s ease-in-out',
88
+ },
89
+ ':host svg:hover': {
90
+ transform: 'scale(1)',
91
+ },
92
+ ':host svg:active': {
93
+ transform: 'scale(1.1)',
94
+ },
95
+ };
96
+ constructor() {
97
+ super();
98
+ this.initAttributes('max', 'min', 'icon', 'step', 'ratingStroke', 'ratingColor', 'emptyStroke', 'emptyColor', 'readonly', 'iconSize', 'hollow');
99
+ }
100
+ content = () => span({ part: 'container' }, span({ part: 'empty' }), span({ part: 'filled' }));
101
+ displayValue(value) {
102
+ const { empty, filled } = this.parts;
103
+ const roundedValue = Math.round((value || 0) / this.step) * this.step;
104
+ filled.style.width = (roundedValue / this.max) * empty.offsetWidth + 'px';
105
+ }
106
+ update = (event) => {
107
+ if (this.readonly) {
108
+ return;
109
+ }
110
+ const { empty } = this.parts;
111
+ const x = event instanceof MouseEvent
112
+ ? event.pageX - empty.getBoundingClientRect().x
113
+ : 0;
114
+ const value = Math.min(Math.max(this.min, Math.round(((x / empty.offsetWidth) * this.max) / this.step + this.step * 0.5) * this.step), this.max);
115
+ if (event.type === 'click') {
116
+ this.value = value;
117
+ }
118
+ else if (event.type === 'mousemove') {
119
+ this.displayValue(value);
120
+ }
121
+ else {
122
+ this.displayValue(this.value || 0);
123
+ }
124
+ };
125
+ handleKey = (event) => {
126
+ let value = Number(this.value);
127
+ if (value == null) {
128
+ value = Math.round((this.min + this.max) * 0.5 * this.step) * this.step;
129
+ }
130
+ let blockEvent = false;
131
+ switch (event.key) {
132
+ case 'ArrowUp':
133
+ case 'ArrowRight':
134
+ value += this.step;
135
+ blockEvent = true;
136
+ break;
137
+ case 'ArrowDown':
138
+ case 'ArrowLeft':
139
+ value -= this.step;
140
+ blockEvent = true;
141
+ break;
142
+ }
143
+ this.value = Math.max(Math.min(value, this.max), this.min);
144
+ if (blockEvent) {
145
+ event.stopPropagation();
146
+ event.preventDefault();
147
+ }
148
+ };
149
+ connectedCallback() {
150
+ super.connectedCallback();
151
+ const { container } = this.parts;
152
+ container.tabIndex = 0;
153
+ container.addEventListener('mousemove', this.update, true);
154
+ container.addEventListener('mouseleave', this.update);
155
+ container.addEventListener('blur', this.update);
156
+ container.addEventListener('click', this.update);
157
+ container.addEventListener('keydown', this.handleKey);
158
+ }
159
+ _renderedIcon = '';
160
+ render() {
161
+ super.render();
162
+ const height = this.iconSize + 'px';
163
+ this.style.setProperty('--rating-fill', this.ratingFill);
164
+ this.style.setProperty('--rating-stroke', this.ratingStroke);
165
+ this.style.setProperty('--empty-fill', this.emptyFill);
166
+ this.style.setProperty('--empty-stroke', this.emptyStroke);
167
+ this.style.setProperty('--xin-icon-size', height);
168
+ if (this.readonly) {
169
+ this.role = 'image';
170
+ }
171
+ else {
172
+ this.role = 'slider';
173
+ }
174
+ this.ariaLabel = `rating ${this.value} out of ${this.max}`;
175
+ this.ariaValueMax = String(this.max);
176
+ this.ariaValueMin = String(this.min);
177
+ this.ariaValueNow = this.value === null ? String(-1) : String(this.value);
178
+ const { empty, filled } = this.parts;
179
+ empty.classList.toggle('hollow', this.hollow);
180
+ if (this._renderedIcon !== this.icon) {
181
+ this._renderedIcon = this.icon;
182
+ for (let i = 0; i < this.max; i++) {
183
+ empty.append(icons[this.icon]());
184
+ filled.append(icons[this.icon]());
185
+ }
186
+ }
187
+ this.displayValue(this.value);
188
+ }
189
+ }
190
+ export const xinRating = XinRating.elementCreator({
191
+ tag: 'xin-rating',
192
+ });
@@ -0,0 +1,35 @@
1
+ import { Component as WebComponent, ElementCreator, PartsMap } from 'tosijs';
2
+ import { XinSelect } from './select';
3
+ export declare function blockStyle(options?: {
4
+ caption: string;
5
+ tagType: string;
6
+ }[]): XinSelect;
7
+ export declare function spacer(width?: string): HTMLSpanElement;
8
+ export declare function elastic(width?: string): HTMLSpanElement;
9
+ export declare function commandButton(title: string, dataCommand: string, icon: SVGElement): HTMLButtonElement;
10
+ export declare const richTextWidgets: () => HTMLSpanElement[];
11
+ interface EditorParts extends PartsMap {
12
+ toolbar: HTMLElement;
13
+ doc: HTMLElement;
14
+ content: HTMLElement;
15
+ }
16
+ export declare class RichText extends WebComponent<EditorParts> {
17
+ widgets: 'none' | 'minimal' | 'default';
18
+ private isInitialized;
19
+ get value(): string;
20
+ set value(docHtml: string);
21
+ blockElement(elt: Node): Element | undefined;
22
+ get selectedBlocks(): any[];
23
+ get selectedText(): string;
24
+ selectionChange: (event: Event, editor: RichText) => void;
25
+ handleSelectChange: (event: Event) => void;
26
+ handleButtonClick: (event: Event) => void;
27
+ content: any[];
28
+ constructor();
29
+ doCommand(command?: string): void;
30
+ updateBlockStyle(): void;
31
+ connectedCallback(): void;
32
+ render(): void;
33
+ }
34
+ export declare const richText: ElementCreator<RichText>;
35
+ export {};