@marianmeres/stuic 2.11.4 → 2.12.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.
@@ -38,7 +38,7 @@
38
38
  import Circle from "../Circle/Circle.svelte";
39
39
  import { Modal } from "../Modal/index.js";
40
40
  import { NotificationsStack } from "../Notifications/notifications-stack.svelte.js";
41
- import SpinnerCircle from "../Spinner/SpinnerCircle.svelte";
41
+ import SpinnerCircleOscillate from "../Spinner/SpinnerCircleOscillate.svelte";
42
42
  import { isTHCNotEmpty, type THC } from "../Thc/Thc.svelte";
43
43
  import { X } from "../X/index.js";
44
44
  import InputWrap from "./_internal/InputWrap.svelte";
@@ -377,7 +377,7 @@
377
377
  {#snippet default_render()}
378
378
  {#if isLoading}
379
379
  <div class="p-2 pl-8 flex items-center justify-center min-h-24">
380
- <SpinnerCircle />
380
+ <SpinnerCircleOscillate />
381
381
  </div>
382
382
  {:else}
383
383
  <div class={["p-2 flex items-center gap-0.5 flex-wrap"]}>
@@ -427,7 +427,7 @@
427
427
  rotate={-90}
428
428
  />
429
429
  {:else}
430
- <SpinnerCircle bgStrokeColor="gray" />
430
+ <SpinnerCircleOscillate bgStrokeColor="gray" />
431
431
  {/if}
432
432
  </span>
433
433
  {/if}
@@ -657,7 +657,7 @@
657
657
  <div
658
658
  class={[
659
659
  "options overflow-y-auto overflow-x-hidden space-y-1 scrollbar-thin",
660
- "h-[220px] max-h-[220px]",
660
+ "h-55 max-h-55",
661
661
  ]}
662
662
  bind:this={optionsBox}
663
663
  tabindex="-1"
@@ -1,136 +1,85 @@
1
1
  <script lang="ts" module>
2
2
  export interface Props {
3
3
  class?: string;
4
- /** One "loop" duration in ms */
5
- duration?: number;
6
- /** Number of "hands" (3-12) */
7
4
  count?: number;
8
- thickness?: "normal" | "thin" | "thick";
9
- height?: "normal" | "tall" | "short";
5
+ thickness?: "thin" | "normal" | "thick";
6
+ height?: "short" | "normal" | "tall";
10
7
  direction?: "cw" | "ccw";
8
+ rounded?: number;
9
+ duration?: number;
11
10
  }
12
11
  </script>
13
12
 
14
13
  <script lang="ts">
15
- import { twMerge } from "../../utils/tw-merge.js";
16
-
17
- // this is quite verbose, but very straight forward implementation,
18
- // and always rendered without any issues (opposed to linear-gradient hackish stuff)
19
-
20
14
  let {
21
- class: _class,
22
- duration = 750,
15
+ class: classProp,
23
16
  count = 8,
24
- thickness = "thick",
17
+ thickness = "normal",
25
18
  height = "normal",
26
19
  direction = "cw",
20
+ rounded = 2,
21
+ duration = 750,
27
22
  }: Props = $props();
28
23
 
29
- let _count = $derived(Math.max(3, Math.min(12, count)));
24
+ const thicknessMap: Record<NonNullable<Props["thickness"]>, number> = {
25
+ thin: 1,
26
+ normal: 2,
27
+ thick: 4,
28
+ };
29
+ const heightMap: Record<NonNullable<Props["height"]>, number> = {
30
+ short: 5,
31
+ normal: 7,
32
+ tall: 10,
33
+ };
30
34
 
31
- let _segments = $derived.by(() => {
32
- let out = [];
33
- for (let i = 0; i < _count; i++) {
34
- out.push({
35
- rotate: (360 / _count) * i,
36
- delay:
37
- (direction === "ccw" ? 1 : -1) * (duration - (duration / _count) * (i + 1)),
38
- duration,
39
- });
40
- }
41
- return out;
42
- });
43
-
44
- let _thickness = $derived(
45
- "thickness-" +
46
- (["normal", "thin", "thick"].includes(thickness) ? thickness : "normal")
47
- );
48
-
49
- let _height = $derived(
50
- "height-" + (["normal", "tall", "short"].includes(height) ? height : "normal")
51
- );
35
+ const barLength = $derived(heightMap[height]);
36
+ const barWidth = $derived(thicknessMap[thickness]);
37
+ const size = $derived(barLength * 3);
38
+ const center = $derived(size / 2);
39
+ const barHeight = $derived(barLength - 1);
52
40
  </script>
53
41
 
54
- <div class="spinner {_thickness} {_height} {twMerge('inline-block w-5', _class)}">
55
- {#each _segments as s}
56
- <div
57
- style={[
58
- `transform: rotate(${s.rotate}deg);`,
59
- `animation-delay: ${s.delay}ms;`,
60
- `animation-duration: ${s.duration}ms;`,
61
- ].join("")}
62
- ></div>
42
+ <div
43
+ class="spinner {classProp ?? ''}"
44
+ style:--size="{size}px"
45
+ style:--duration="{duration}ms"
46
+ >
47
+ {#each Array(count) as _, i}
48
+ {@const angle = (360 / count) * i}
49
+ {@const delay = direction === "ccw" ? i / count : (count - i) / count}
50
+ <span
51
+ class="bar"
52
+ style:width="{barWidth}px"
53
+ style:height="{barHeight}px"
54
+ style:border-radius="{rounded}px"
55
+ style:transform-origin="center {center}px"
56
+ style:transform="translateX(-50%) rotate({angle}deg)"
57
+ style:animation-delay="{-delay * duration}ms"
58
+ ></span>
63
59
  {/each}
64
60
  </div>
65
61
 
66
62
  <style>
67
- .spinner,
68
- .spinner div,
69
- .spinner div:after {
70
- box-sizing: border-box;
71
- }
72
-
73
63
  .spinner {
74
- /* display: inline-block; */
75
64
  position: relative;
76
- aspect-ratio: 1/1;
77
- pointer-events: none;
65
+ width: var(--size);
66
+ height: var(--size);
78
67
  }
79
68
 
80
- .spinner div {
81
- width: 100%;
82
- height: 100%;
69
+ .bar {
83
70
  position: absolute;
84
- inset: 0;
85
- /* animation: spinner 1.2s linear infinite; */
86
- animation-name: spinner;
87
- animation-timing-function: linear;
88
- animation-iteration-count: infinite;
89
- }
90
-
91
- .spinner div:after {
92
- content: " ";
93
- display: block;
94
- position: absolute;
95
-
96
- top: 0;
97
- /* left: 46%;
98
- width: 8%;
99
- height: 27%; */
100
- border-radius: 35%;
71
+ left: 50%;
72
+ top: 0px;
101
73
  background: currentColor;
102
- }
103
- /* thickness */
104
- .spinner.thickness-thin div:after {
105
- left: 47.5%;
106
- width: 5%;
107
- }
108
- .spinner.thickness-normal div:after {
109
- left: 46%;
110
- width: 8%;
111
- }
112
- .spinner.thickness-thick div:after {
113
- left: 44.5%;
114
- width: 11%;
115
- }
116
-
117
- /* height */
118
- .spinner.height-short div:after {
119
- height: 21%;
120
- }
121
- .spinner.height-normal div:after {
122
- height: 27%;
123
- }
124
- .spinner.height-tall div:after {
125
- height: 33%;
74
+ animation: fade var(--duration) linear infinite;
126
75
  }
127
76
 
128
- @keyframes spinner {
129
- 0% {
77
+ @keyframes fade {
78
+ from {
130
79
  opacity: 1;
131
80
  }
132
- 100% {
133
- opacity: 0;
81
+ to {
82
+ opacity: 0.12;
134
83
  }
135
84
  }
136
85
  </style>
@@ -1,12 +1,11 @@
1
1
  export interface Props {
2
2
  class?: string;
3
- /** One "loop" duration in ms */
4
- duration?: number;
5
- /** Number of "hands" (3-12) */
6
3
  count?: number;
7
- thickness?: "normal" | "thin" | "thick";
8
- height?: "normal" | "tall" | "short";
4
+ thickness?: "thin" | "normal" | "thick";
5
+ height?: "short" | "normal" | "tall";
9
6
  direction?: "cw" | "ccw";
7
+ rounded?: number;
8
+ duration?: number;
10
9
  }
11
10
  declare const Spinner: import("svelte").Component<Props, {}, "">;
12
11
  type Spinner = ReturnType<typeof Spinner>;
@@ -1,47 +1,62 @@
1
1
  <script lang="ts" module>
2
2
  export interface Props {
3
3
  class?: string;
4
- bgStrokeColor?: string;
5
- strokeWidth?: number;
6
- noOscillate?: boolean;
7
- rotateDuration?: string;
4
+ /** One "loop" duration in ms */
5
+ duration?: number;
6
+ /** Border thickness preset */
7
+ thickness?: "normal" | "thin" | "thick";
8
+ /** Rotation direction */
9
+ direction?: "cw" | "ccw";
8
10
  }
9
11
  </script>
10
12
 
11
13
  <script lang="ts">
12
- import { createTickerRAF } from "@marianmeres/ticker";
13
- import { onDestroy } from "svelte";
14
- import { oscillate } from "../../utils/oscillate.js";
15
14
  import { twMerge } from "../../utils/tw-merge.js";
16
- import Circle from "../Circle/Circle.svelte";
17
15
 
18
16
  let {
19
- class: classProp = "",
20
- bgStrokeColor = "rgba(0 0 0 / .1)",
21
- strokeWidth,
22
- noOscillate,
23
- rotateDuration = ".75s",
17
+ class: classProp,
18
+ duration = 750,
19
+ thickness = "normal",
20
+ direction = "cw",
24
21
  }: Props = $props();
25
22
 
26
- /**
27
- * NOTE: we happen to have 4 distinct values here which effect the overall look and feel...
28
- * 1. the tick frequency
29
- * 2. the oscillation time input (seconds)
30
- * 3. the oscillation speed factor (1)
31
- * 4. the animation-spin duration
32
- */
23
+ let _thickness = $derived(
24
+ "thickness-" +
25
+ (["normal", "thin", "thick"].includes(thickness) ? thickness : "normal")
26
+ );
27
+ </script>
33
28
 
34
- const ticker = createTickerRAF(50, true);
35
- let completeness = $derived(noOscillate ? 0.66 : oscillate($ticker / 1000, 0.15, 0.85));
29
+ <span
30
+ class={twMerge("stuic-spinner-basic inline-block size-5", _thickness, classProp)}
31
+ style="animation-duration: {duration}ms; animation-direction: {direction === 'ccw'
32
+ ? 'reverse'
33
+ : 'normal'};"
34
+ ></span>
36
35
 
37
- onDestroy(ticker.stop);
38
- </script>
36
+ <style>
37
+ .stuic-spinner-basic {
38
+ box-sizing: border-box;
39
+ border-radius: 50%;
40
+ border-style: solid;
41
+ border-color: currentColor;
42
+ border-top-color: transparent;
43
+ animation: spin linear infinite;
44
+ }
45
+
46
+ /* Thickness presets */
47
+ .stuic-spinner-basic.thickness-thin {
48
+ border-width: 1px;
49
+ }
50
+ .stuic-spinner-basic.thickness-normal {
51
+ border-width: 2px;
52
+ }
53
+ .stuic-spinner-basic.thickness-thick {
54
+ border-width: 4px;
55
+ }
39
56
 
40
- <Circle
41
- animateCompletenessMs={0}
42
- {completeness}
43
- class={twMerge("stuic-spinner-circle animate-spin", classProp)}
44
- {bgStrokeColor}
45
- {strokeWidth}
46
- style="animation-duration: {rotateDuration}"
47
- />
57
+ @keyframes spin {
58
+ to {
59
+ transform: rotate(360deg);
60
+ }
61
+ }
62
+ </style>
@@ -1,9 +1,11 @@
1
1
  export interface Props {
2
2
  class?: string;
3
- bgStrokeColor?: string;
4
- strokeWidth?: number;
5
- noOscillate?: boolean;
6
- rotateDuration?: string;
3
+ /** One "loop" duration in ms */
4
+ duration?: number;
5
+ /** Border thickness preset */
6
+ thickness?: "normal" | "thin" | "thick";
7
+ /** Rotation direction */
8
+ direction?: "cw" | "ccw";
7
9
  }
8
10
  declare const SpinnerCircle: import("svelte").Component<Props, {}, "">;
9
11
  type SpinnerCircle = ReturnType<typeof SpinnerCircle>;
@@ -0,0 +1,47 @@
1
+ <script lang="ts" module>
2
+ export interface Props {
3
+ class?: string;
4
+ bgStrokeColor?: string;
5
+ strokeWidth?: number;
6
+ noOscillate?: boolean;
7
+ rotateDuration?: string;
8
+ }
9
+ </script>
10
+
11
+ <script lang="ts">
12
+ import { createTickerRAF } from "@marianmeres/ticker";
13
+ import { onDestroy } from "svelte";
14
+ import { oscillate } from "../../utils/oscillate.js";
15
+ import { twMerge } from "../../utils/tw-merge.js";
16
+ import Circle from "../Circle/Circle.svelte";
17
+
18
+ let {
19
+ class: classProp = "",
20
+ bgStrokeColor = "rgba(0 0 0 / .1)",
21
+ strokeWidth,
22
+ noOscillate,
23
+ rotateDuration = ".75s",
24
+ }: Props = $props();
25
+
26
+ /**
27
+ * NOTE: we happen to have 4 distinct values here which effect the overall look and feel...
28
+ * 1. the tick frequency
29
+ * 2. the oscillation time input (seconds)
30
+ * 3. the oscillation speed factor (1)
31
+ * 4. the animation-spin duration
32
+ */
33
+
34
+ const ticker = createTickerRAF(50, true);
35
+ let completeness = $derived(noOscillate ? 0.66 : oscillate($ticker / 1000, 0.15, 0.85));
36
+
37
+ onDestroy(ticker.stop);
38
+ </script>
39
+
40
+ <Circle
41
+ animateCompletenessMs={0}
42
+ {completeness}
43
+ class={twMerge("stuic-spinner-circle animate-spin", classProp)}
44
+ {bgStrokeColor}
45
+ {strokeWidth}
46
+ style="animation-duration: {rotateDuration}"
47
+ />
@@ -0,0 +1,10 @@
1
+ export interface Props {
2
+ class?: string;
3
+ bgStrokeColor?: string;
4
+ strokeWidth?: number;
5
+ noOscillate?: boolean;
6
+ rotateDuration?: string;
7
+ }
8
+ declare const SpinnerCircleOscillate: import("svelte").Component<Props, {}, "">;
9
+ type SpinnerCircleOscillate = ReturnType<typeof SpinnerCircleOscillate>;
10
+ export default SpinnerCircleOscillate;
@@ -1,3 +1,4 @@
1
1
  export { default as Spinner, type Props as SpinnerProps } from "./Spinner.svelte";
2
2
  export { default as SpinnerCircle, type Props as SpinnerCircleProps, } from "./SpinnerCircle.svelte";
3
+ export { default as SpinnerCircleOscillate, type Props as SpinnerCircleOscillateProps, } from "./SpinnerCircleOscillate.svelte";
3
4
  export { spinnerCreateBackAndForthCharFrames, default as SpinnerUnicode, type Props as SpinnerUnicodeProps, type SpinnerUnicodeVariant, } from "./SpinnerUnicode.svelte";
@@ -1,3 +1,4 @@
1
1
  export { default as Spinner } from "./Spinner.svelte";
2
2
  export { default as SpinnerCircle, } from "./SpinnerCircle.svelte";
3
+ export { default as SpinnerCircleOscillate, } from "./SpinnerCircleOscillate.svelte";
3
4
  export { spinnerCreateBackAndForthCharFrames, default as SpinnerUnicode, } from "./SpinnerUnicode.svelte";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "2.11.4",
3
+ "version": "2.12.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",