wx-svelte-core 2.1.0 → 2.2.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wx-svelte-core",
3
- "version": "2.1.0",
4
- "description": "SVAR Svelte Core library, a collection of form controls and UI components",
3
+ "version": "2.2.0",
4
+ "description": "SVAR Svelte Core - Svelte UI library of 20+ components and form controls",
5
5
  "productTag": "core",
6
6
  "productTrial": false,
7
7
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "homepage": "https://svar.dev/svelte/core/",
34
34
  "dependencies": {
35
- "wx-core-locales": "2.1.0",
35
+ "wx-core-locales": "2.2.0",
36
36
  "wx-lib-dom": "0.8.0",
37
37
  "wx-lib-svelte": "0.5.1"
38
38
  },
package/readme.md CHANGED
@@ -18,12 +18,20 @@
18
18
 
19
19
  </div>
20
20
 
21
- [SVAR Core library](https://svar.dev/svelte/core/) offers a set of 20+ ready-made Svelte UI components: form controls, popups, date and time picker, toast notifications, and more.
22
- All components are lightweight, responsive, fast-performing, and available in light and dark skins.
21
+ [SVAR Core library](https://svar.dev/svelte/core/) offers a set of 20+ ready-made Svelte UI components: form controls, popups, date and time picker, toast notifications, and more. All components are lightweight, responsive, fast-performing, and available in light and dark skins.
23
22
 
24
- <img src="https://cdn.svar.dev/public/core-ui-dark.jpg" alt="SVAR Core Library - Dark Skin" style="width: 600px;">
23
+ <img src="https://svar.dev/images/github/github-core.png" alt="SVAR Core - Svelte UI Components Library" style="width: 752px;">
25
24
 
26
- In addition to the Core library, you can use the following SVAR components to build unified app UIs:
25
+ SVAR Core library includes the following components:
26
+
27
+ - buttons & form controls,
28
+ - calendar (datepicker),
29
+ - popups,
30
+ - notifications,
31
+ - sliding sidebar,
32
+ - tabs, and more.
33
+
34
+ Additionally, you can use these SVAR Svelte components to build unified app interfaces:
27
35
 
28
36
  - [Menu](https://www.npmjs.com/package/wx-svelte-menu)
29
37
  - [Toolbar](https://www.npmjs.com/package/wx-svelte-toolbar)
@@ -31,11 +39,11 @@ In addition to the Core library, you can use the following SVAR components to bu
31
39
  - [Comments](https://www.npmjs.com/package/wx-svelte-comments)
32
40
  - [Tasklist](https://www.npmjs.com/package/wx-svelte-tasklist)
33
41
 
34
- ### Svelte 4 and Svelte 5 versions
42
+ ### :gear: Svelte 4 and Svelte 5 versions
35
43
 
36
- There are two versions of the library: the 1.x version, designed to work with Svelte 4, and the 2.x version, created for Svelte 5. Please note that the 2.x version is in beta and may contain some instabilities.
44
+ There are two versions of the library: the 1.x version - designed to work with Svelte 4, and the 2.x version - created for Svelte 5.
37
45
 
38
- To use the SVAR Core beta for Svelte 5, install it as follows:
46
+ To use the SVAR Core for Svelte 5, install it as follows:
39
47
 
40
48
  ```
41
49
  npm install wx-svelte-core
@@ -47,7 +55,7 @@ To use the SVAR Core for Svelte 4:
47
55
  npm install wx-svelte-core@1.3.0
48
56
  ```
49
57
 
50
- # :hammer_and_wrench: How to Use
58
+ ### :hammer_and_wrench: How to Use
51
59
 
52
60
  To use any of the Core components, simply import the package and include the desired component in your Svelte file:
53
61
 
@@ -78,10 +78,6 @@
78
78
  outline: none;
79
79
  }
80
80
 
81
- .wx-button:active:not(:global([disabled])) {
82
- opacity: 0.8;
83
- }
84
-
85
81
  .wx-button[disabled] {
86
82
  cursor: not-allowed;
87
83
  background: var(--wx-color-disabled);
@@ -130,17 +126,41 @@
130
126
  color: var(--wx-color-primary-font);
131
127
  }
132
128
 
129
+ .wx-pressed,
130
+ .wx-pressed:hover,
131
+ .wx-pressed:active,
132
+ .wx-pressed[disabled] {
133
+ background-color: var(--wx-button-pressed);
134
+ box-shadow: var(--wx-button-box-shadow);
135
+ }
136
+
137
+ .wx-primary.wx-pressed:not(:global([disabled])),
138
+ .wx-primary.wx-pressed:hover:not(:global([disabled])),
139
+ .wx-primary.wx-pressed:active:not(:global([disabled])) {
140
+ background-color: var(--wx-button-primary-pressed);
141
+ box-shadow: var(--wx-button-primary-box-shadow);
142
+ }
143
+
144
+ .wx-danger.wx-pressed:not(:global([disabled])),
145
+ .wx-danger.wx-pressed:hover:not(:global([disabled])),
146
+ .wx-danger.wx-pressed:active:not(:global([disabled])) {
147
+ background-color: var(--wx-button-danger-pressed);
148
+ box-shadow: var(--wx-button-primary-box-shadow);
149
+ }
150
+
133
151
  .wx-secondary {
134
152
  background: var(--wx-color-secondary);
135
153
  color: var(--wx-color-secondary-font);
136
154
  border-color: var(--wx-color-secondary-border);
137
155
  }
138
- .wx-secondary:hover:not(:global([disabled])),
156
+ .wx-secondary:hover:not(:global([disabled])) {
157
+ background: var(--wx-color-secondary-hover);
158
+ }
139
159
  .wx-secondary.wx-pressed:not(:global([disabled])),
140
160
  .wx-secondary.wx-pressed:hover:not(:global([disabled])),
141
161
  .wx-secondary.wx-pressed:active:not(:global([disabled])) {
142
162
  background: var(--wx-color-secondary-hover);
143
- color: var(--wx-color-secondary-font-hover);
163
+ box-shadow: var(--wx-button-primary-box-shadow);
144
164
  }
145
165
  .wx-secondary[disabled] {
146
166
  border-color: var(--wx-color-secondary-border-disabled);
@@ -165,16 +185,4 @@
165
185
  .wx-link[disabled] {
166
186
  color: var(--wx-color-font-disabled);
167
187
  }
168
-
169
- .wx-pressed,
170
- .wx-pressed:hover,
171
- .wx-pressed:active,
172
- .wx-pressed[disabled] {
173
- opacity: 0.8;
174
- background-image: linear-gradient(
175
- rgba(0, 0, 0, 0.1) 0%,
176
- rgba(0, 0, 0, 0.1) 100%
177
- );
178
- box-shadow: inset 0 2px 2px 1px rgba(0, 0, 0, 0.15);
179
- }
180
188
  </style>
@@ -1,11 +1,13 @@
1
1
  <script>
2
2
  import Panel from "./calendar/Panel.svelte";
3
3
 
4
+ import Locale from "../Locale.svelte";
5
+
4
6
  let {
5
7
  value = $bindable(),
6
8
  current = $bindable(),
7
9
  markers = null,
8
- buttons = true,
10
+ buttons = ["clear", "today"],
9
11
  onchange: change,
10
12
  } = $props();
11
13
 
@@ -28,4 +30,6 @@
28
30
  }
29
31
  </script>
30
32
 
31
- <Panel {value} bind:current {markers} {buttons} {onchange} />
33
+ <Locale>
34
+ <Panel {value} bind:current {markers} {buttons} {onchange} />
35
+ </Locale>
@@ -1,306 +1,10 @@
1
1
  <script>
2
- import { onMount, getContext } from "svelte";
3
- import Button from "./Button.svelte";
2
+ import Locale from "../Locale.svelte";
3
+ import Layout from "./colorboard/Layout.svelte";
4
4
 
5
- //helpers
6
- import { sliderMove } from "./helpers/sliderMove";
7
- import colorTransformator from "./helpers/colorTransformator";
8
- import { parseColor } from "./helpers/colorValidation.js";
9
-
10
- let { value = $bindable("#65D3B3"), button = false, onchange } = $props();
11
-
12
- let block;
13
-
14
- const _ = getContext("wx-i18n").getGroup("core");
15
-
16
- const BLOCK = "Block";
17
- const LINE = "Line";
18
-
19
- let blockTop = $state();
20
- let blockLeft = $state();
21
- let hueColor = $state();
22
- let colorLine = $state();
23
- let lineLeft = $state();
24
-
25
- let color = $derived(parseColor(value) || "#65D3B3");
26
- let blockColor = $derived(colorTransformator.hvsToHex(hueColor, 1, 1));
27
-
28
- function moveBlockSlider(dx, dy) {
29
- const { width, height } = block.getBoundingClientRect();
30
-
31
- if (dy < 0) dy = 0;
32
- else if (dy > height) dy = height;
33
-
34
- if (dx < 0) dx = 0;
35
- else if (dx > width) dx = width;
36
-
37
- blockTop = dy;
38
- blockLeft = dx;
39
-
40
- setCurrentColor();
41
- }
42
-
43
- function setCurrentColor(lineSliderMove) {
44
- let _sValue, _vValue;
45
-
46
- if (lineSliderMove) {
47
- [, _sValue, _vValue] = colorTransformator.hexToHvs(color);
48
- } else {
49
- const { width, height } = block.getBoundingClientRect();
50
-
51
- const pxX = width / 100;
52
- const pxY = height / 100;
53
-
54
- _sValue = Math.ceil(blockLeft / pxX) / 100;
55
- _vValue = Math.ceil(Math.abs(blockTop / pxY - 100)) / 100;
56
- }
57
-
58
- value = colorTransformator.hvsToHex(hueColor, _sValue, _vValue);
59
- onchange && onchange({ value, input: true });
60
- }
61
-
62
- function moveLineSlider(dx) {
63
- const width = colorLine.getBoundingClientRect().width;
64
-
65
- if (dx < 0) dx = 0;
66
- else if (dx > width) dx = width;
67
-
68
- toggleLineColor(dx, width);
69
- }
70
-
71
- function toggleLineColor(dx, width) {
72
- width = width || colorLine.getBoundingClientRect().width;
73
-
74
- lineLeft = dx;
75
-
76
- const h = Math.round((lineLeft * 359) / width);
77
- hueColor = Math.max(Math.min(h, 359), 0);
78
-
79
- setCurrentColor(true);
80
- }
81
-
82
- onMount(() => setSlidersPosition());
83
-
84
- function setSlidersPosition() {
85
- const [h, s, v] = colorTransformator.hexToHvs(color);
86
- const { width, height } = block.getBoundingClientRect();
87
- hueColor = h;
88
-
89
- lineLeft = (h * colorLine.getBoundingClientRect().width) / 359;
90
- blockLeft = s * width;
91
- blockTop = Math.abs(height * (v - 1));
92
- }
93
-
94
- function handleChange({ target }) {
95
- const newColor = parseColor(target.value);
96
-
97
- value = newColor;
98
- onchange && onchange({ value, input: true });
99
- if (newColor) {
100
- setSlidersPosition();
101
- }
102
- }
103
-
104
- function handleSelect(ev) {
105
- ev.stopPropagation();
106
- onchange && onchange({ value: color });
107
- }
108
-
109
- function keydown(ev) {
110
- const slider = ev.target;
111
- const isSliderBlock = slider === BLOCK;
112
- const isSliderLine = slider === LINE;
113
-
114
- let css = window.getComputedStyle(slider);
115
- let left = parseFloat(css.left);
116
- let top = parseFloat(css.top);
117
- const code = ev.code;
118
-
119
- if (isSliderBlock) {
120
- switch (code) {
121
- case "ArrowLeft": {
122
- left--;
123
- break;
124
- }
125
- case "ArrowRight": {
126
- left++;
127
- break;
128
- }
129
- case "ArrowDown": {
130
- top++;
131
- break;
132
- }
133
- case "ArrowUp": {
134
- top--;
135
- break;
136
- }
137
- default:
138
- return;
139
- }
140
-
141
- moveBlockSlider(left, top);
142
- }
143
-
144
- if (isSliderLine) {
145
- if (code === "ArrowLeft" || code === "ArrowDown") left--;
146
- else if (code === "ArrowRight" || code === "ArrowUp") left++;
147
- else return;
148
- moveLineSlider(left);
149
- }
150
-
151
- ev.preventDefault();
152
- }
5
+ let { value = $bindable("#65D3B3"), ...props } = $props();
153
6
  </script>
154
7
 
155
- <div class="wx-colorboard">
156
- <div
157
- class="wx-color-block"
158
- style="background: {blockColor};"
159
- bind:this={block}
160
- use:sliderMove={{ moveBlockSlider }}
161
- >
162
- <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
163
- <!-- svelte-ignore a11y_no_static_element_interactions -->
164
- <div
165
- class="wx-color-block-slider wx-slider"
166
- style="background: {color}; top: {blockTop}px; left:{blockLeft}px;"
167
- tabindex="0"
168
- data-slider={BLOCK}
169
- onkeydown={keydown}
170
- ></div>
171
- </div>
172
- <div
173
- class="wx-color-line"
174
- bind:this={colorLine}
175
- use:sliderMove={{ moveLineSlider }}
176
- >
177
- <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
178
- <!-- svelte-ignore a11y_no_static_element_interactions -->
179
- <div
180
- class="wx-color-line-slider wx-slider"
181
- style="background: {blockColor}; left: {lineLeft}px;"
182
- tabindex="0"
183
- data-slider={LINE}
184
- onkeydown={keydown}
185
- ></div>
186
- </div>
187
- <div class="wx-color-controls">
188
- <div class="wx-color" style="background: {color}"></div>
189
- <input type="text" class="wx-text" bind:value onchange={handleChange} />
190
- </div>
191
- {#if button}
192
- <Button onclick={handleSelect} type="secondary">{_("select")}</Button>
193
- {/if}
194
- </div>
195
-
196
- <style>
197
- .wx-colorboard {
198
- display: flex;
199
- flex-direction: column;
200
- gap: 12px;
201
- padding: 8px;
202
- width: 100%;
203
- }
204
-
205
- .wx-color-block {
206
- height: 140px;
207
- width: 100%;
208
- position: relative;
209
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
210
- }
211
-
212
- .wx-color-block::before,
213
- .wx-color-block::after {
214
- content: "";
215
- width: 100%;
216
- height: 100%;
217
- position: absolute;
218
- }
219
- .wx-color-block:before {
220
- background-image: linear-gradient(0deg, #000, hsla(0, 0%, 100%, 0));
221
- z-index: 2;
222
- }
223
- .wx-color-block::after {
224
- background-image: linear-gradient(90deg, #fff, hsla(20, 42%, 65%, 0));
225
- z-index: 1;
226
- }
227
-
228
- .wx-color-block-slider {
229
- height: 16px;
230
- width: 16px;
231
- margin: -8px 0 0 -8px;
232
- }
233
-
234
- .wx-slider {
235
- border: 2px solid white;
236
- border-radius: 50%;
237
- position: absolute;
238
- z-index: 3;
239
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
240
- }
241
-
242
- .wx-slider:focus,
243
- .wx-slider:hover {
244
- outline: none;
245
- box-shadow:
246
- 0 1px 3px rgba(0, 0, 0, 0.2),
247
- inset 0 0 4px #ffffff;
248
- }
249
-
250
- .wx-color-line {
251
- width: 100%;
252
- height: 8px;
253
- background-image: linear-gradient(
254
- 90deg,
255
- red,
256
- #ff0 17%,
257
- #0f0 33%,
258
- #0ff 50%,
259
- #00f 67%,
260
- #f0f 83%,
261
- red
262
- );
263
- position: relative;
264
- border-radius: 6px;
265
- }
266
-
267
- .wx-color-line-slider {
268
- height: 14px;
269
- width: 14px;
270
- margin: 0 0 0 -7px;
271
- top: -4px;
272
- }
273
-
274
- .wx-color-controls {
275
- display: flex;
276
- flex-wrap: wrap;
277
- justify-content: space-between;
278
- }
279
-
280
- .wx-color,
281
- .wx-text {
282
- width: calc(50% - 4px);
283
- }
284
-
285
- .wx-color {
286
- height: 32px;
287
- }
288
-
289
- .wx-text {
290
- outline: none;
291
- background: var(--wx-input-background);
292
- border: var(--wx-input-border);
293
- border-radius: var(--wx-input-border-radius);
294
- font-family: var(--wx-input-font-family);
295
- font-size: var(--wx-input-font-size);
296
- line-height: var(--wx-input-line-height);
297
- font-weight: var(--wx-input-font-weight);
298
- text-align: var(--wx-input-text-align);
299
- color: var(--wx-input-font-color);
300
- padding: var(--wx-input-padding);
301
- }
302
-
303
- .wx-text:focus {
304
- border: var(--wx-input-border-focus);
305
- }
306
- </style>
8
+ <Locale>
9
+ <Layout bind:value {...props} />
10
+ </Locale>
@@ -21,11 +21,12 @@
21
21
  let textInput = $state("");
22
22
 
23
23
  let text = $derived.by(() => {
24
- return filterActive
25
- ? textInput
26
- : value || value === 0
27
- ? (textOptions || options).find(a => a.id === value)[textField]
28
- : "";
24
+ if (filterActive) return textInput;
25
+ if (value || value === 0) {
26
+ const option = (textOptions || options).find(a => a.id === value);
27
+ if (option) return option[textField];
28
+ }
29
+ return "";
29
30
  });
30
31
 
31
32
  let filteredOptions = $derived.by(() => {
@@ -1,110 +1,10 @@
1
1
  <script>
2
- import { getContext } from "svelte";
3
- import { uid, dateToString } from "wx-lib-dom";
2
+ import Locale from "../Locale.svelte";
3
+ import Layout from "./datepicker/Layout.svelte";
4
4
 
5
- import Text from "./Text.svelte";
6
- import Dropdown from "./Dropdown.svelte";
7
- import Calendar from "./Calendar.svelte";
8
-
9
- let {
10
- value = $bindable(),
11
- id = uid(),
12
- disabled = false,
13
- error = false,
14
- width = "unset",
15
- align = "start",
16
- placeholder = "",
17
- format = "",
18
- buttons = true,
19
- css = "",
20
- title = "",
21
- editable = false,
22
- clear = false,
23
- onchange: change,
24
- } = $props();
25
-
26
- const { calendar: calendarLocale, formats } =
27
- getContext("wx-i18n").getRaw();
28
- const f = format || formats.dateFormat;
29
- let dateFormat =
30
- typeof f === "function" ? f : dateToString(f, calendarLocale);
31
-
32
- let popup = $state();
33
-
34
- function oncancel() {
35
- popup = false;
36
- }
37
-
38
- function doChange(v) {
39
- // skip "select" event if the same value
40
- // or different objects with the same value
41
- const skipEvent =
42
- v === value ||
43
- (v && value && v.valueOf() === value.valueOf()) ||
44
- (!v && !value);
45
-
46
- value = v;
47
- if (!skipEvent) {
48
- change && change({ value });
49
- }
50
-
51
- // fire after on-click finished
52
- setTimeout(oncancel, 1);
53
- }
54
-
55
- const formattedValue = $derived(value ? dateFormat(value) : "");
56
-
57
- function onchange({ value: v, input }) {
58
- if (!editable && !clear) return;
59
- if (input) return;
60
-
61
- // convert to date, but ignore empty string input
62
- let date =
63
- typeof editable === "function"
64
- ? editable(v)
65
- : v
66
- ? new Date(v)
67
- : null;
68
-
69
- // if date is invalid ( incorrect text input ) then use old value
70
- // else use the entered date
71
- // in any case fallback to null, to prevent undefined as value
72
- date = isNaN(date) ? value || null : date || null;
73
- doChange(date);
74
- }
5
+ let { value = $bindable(), ...props } = $props();
75
6
  </script>
76
7
 
77
- <svelte:window onscroll={oncancel} />
78
-
79
- <!-- svelte-ignore a11y_click_events_have_key_events -->
80
- <!-- svelte-ignore a11y_no_static_element_interactions -->
81
- <div class="wx-datepicker" onclick={() => (popup = true)}>
82
- <Text
83
- {css}
84
- {title}
85
- value={formattedValue}
86
- {id}
87
- readonly={!editable}
88
- {disabled}
89
- {error}
90
- {placeholder}
91
- oninput={oncancel}
92
- {onchange}
93
- icon="wxi-calendar"
94
- inputStyle="cursor: pointer; width: 100%; padding-right: calc(var(--wx-input-icon-size) + var(--wx-input-icon-indent) * 2);"
95
- {clear}
96
- />
97
-
98
- {#if popup && !disabled}
99
- <Dropdown {oncancel} {width} {align} autoFit={!!align}>
100
- <Calendar {buttons} {value} onchange={e => doChange(e.value)} />
101
- </Dropdown>
102
- {/if}
103
- </div>
104
-
105
- <style>
106
- .wx-datepicker {
107
- position: relative;
108
- width: var(--wx-input-width);
109
- }
110
- </style>
8
+ <Locale>
9
+ <Layout bind:value {...props} />
10
+ </Locale>