@danielito1996/compose-svelted 0.2.7 → 0.2.8-alpha01

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 (70) hide show
  1. package/README.md +196 -113
  2. package/dist/components/AppRoot.svelte +26 -14
  3. package/dist/components/Surface.svelte +29 -19
  4. package/dist/components/Text.svelte +37 -23
  5. package/dist/components/buttons/Button.svelte +66 -34
  6. package/dist/components/buttons/CheckButton.svelte +2 -2
  7. package/dist/components/layouts/Alignment.d.ts +40 -18
  8. package/dist/components/layouts/Alignment.js +40 -18
  9. package/dist/components/layouts/Arrangement.d.ts +27 -11
  10. package/dist/components/layouts/Arrangement.js +34 -41
  11. package/dist/components/layouts/Box.svelte +54 -25
  12. package/dist/components/layouts/Box.svelte.d.ts +8 -1
  13. package/dist/components/layouts/Column.svelte +52 -23
  14. package/dist/components/layouts/Column.svelte.d.ts +10 -2
  15. package/dist/components/layouts/LayoutContext.d.ts +1 -0
  16. package/dist/components/layouts/LayoutContext.js +1 -0
  17. package/dist/components/layouts/LazyColumn.svelte +12 -12
  18. package/dist/components/layouts/LazyRow.svelte +81 -45
  19. package/dist/components/layouts/LazyRow.svelte.d.ts +3 -6
  20. package/dist/components/layouts/Row.svelte +52 -23
  21. package/dist/components/layouts/Row.svelte.d.ts +10 -2
  22. package/dist/components/layouts/Scaffold.svelte +86 -73
  23. package/dist/components/layouts/Scaffold.svelte.d.ts +5 -1
  24. package/dist/components/layouts/resolveAlignment.d.ts +25 -0
  25. package/dist/components/layouts/resolveAlignment.js +48 -0
  26. package/dist/components/layouts/resolveFlexAlignSelf.d.ts +6 -0
  27. package/dist/components/layouts/resolveFlexAlignSelf.js +8 -0
  28. package/dist/components/motion/motion/AnimatedContent.svelte +41 -0
  29. package/dist/components/motion/{AnimatedContent.svelte.d.ts → motion/AnimatedContent.svelte.d.ts} +1 -1
  30. package/dist/components/motion/{AnimatedVisibility.svelte → motion/AnimatedVisibility.svelte} +3 -3
  31. package/dist/components/motion/{AnimatedVisibility.svelte.d.ts → motion/AnimatedVisibility.svelte.d.ts} +1 -1
  32. package/dist/components/motion/motion/AnimationSpec.d.ts +6 -0
  33. package/dist/components/motion/motion/AnimationSpec.js +1 -0
  34. package/dist/components/motion/motion/ContentTransition.d.ts +5 -0
  35. package/dist/components/motion/motion/ContentTransition.js +1 -0
  36. package/dist/components/motion/motion/applyAnimation.d.ts +0 -0
  37. package/dist/components/motion/motion/applyAnimation.js +0 -0
  38. package/dist/components/motion/motion/contentTransitions.d.ts +4 -0
  39. package/dist/components/motion/motion/contentTransitions.js +22 -0
  40. package/dist/components/motion/motion/transitions.d.ts +7 -0
  41. package/dist/components/motion/motion/transitions.js +70 -0
  42. package/dist/components/textFields/BaseTextField.svelte +4 -3
  43. package/dist/components/textFields/BaseTextField.svelte.d.ts +1 -0
  44. package/dist/components/textFields/OutlinedTextField.svelte +8 -7
  45. package/dist/components/textFields/TextField.svelte +8 -8
  46. package/dist/core/modifier/Modifier.d.ts +11 -171
  47. package/dist/core/modifier/Modifier.js +8 -170
  48. package/dist/core/modifier/ModifierImpl.d.ts +29 -17
  49. package/dist/core/modifier/ModifierImpl.js +112 -151
  50. package/dist/core/motion/AnimationSpec.d.ts +1 -6
  51. package/dist/core/motion/ContentTransition.d.ts +1 -5
  52. package/dist/core/motion/applyAnimation.d.ts +2 -0
  53. package/dist/core/motion/applyAnimation.js +3 -0
  54. package/dist/core/motion/contentTransitions.d.ts +1 -4
  55. package/dist/core/motion/contentTransitions.js +1 -22
  56. package/dist/core/motion/transitions.d.ts +1 -7
  57. package/dist/core/motion/transitions.js +1 -70
  58. package/dist/core/navigation/NavHost.svelte +46 -45
  59. package/dist/core/styles/baseline-safe.css +34 -0
  60. package/dist/core/styles/baseline.css +45 -0
  61. package/dist/core/theme/ColorScheme.d.ts +2 -0
  62. package/dist/core/theme/ColorScheme.js +2 -0
  63. package/dist/core/theme/ComposeTheme.svelte +36 -21
  64. package/dist/core/theme/colors.d.ts +2 -0
  65. package/dist/core/theme/defaults/darkColors.js +2 -0
  66. package/dist/core/theme/defaults/lightColors.js +2 -0
  67. package/dist/index.d.ts +48 -129
  68. package/dist/index.js +7 -2
  69. package/package.json +73 -58
  70. package/dist/components/motion/AnimatedContent.svelte +0 -34
@@ -1,20 +1,42 @@
1
+ /**
2
+ * Alignment — tokens de alineación type-safe con branded types.
3
+ *
4
+ * Los objetos son opacos: nunca se puede pasar un VerticalAlignment donde
5
+ * se espera un HorizontalAlignment, aunque ambos representen "center" en CSS.
6
+ *
7
+ * Filosofía Jetpack Compose:
8
+ * - HorizontalAlignment → eje cross de Column
9
+ * - VerticalAlignment → eje cross de Row
10
+ * - BoxAlignment → alineación compuesta para Box (stack)
11
+ */
12
+ // ─── Helpers internos ────────────────────────────────────────────────────────
13
+ function h(cssValue) {
14
+ return { _brand: 'HorizontalAlignment', cssValue: cssValue };
15
+ }
16
+ function v(cssValue) {
17
+ return { _brand: 'VerticalAlignment', cssValue: cssValue };
18
+ }
19
+ function box(horizontal, vertical) {
20
+ return { _brand: 'BoxAlignment', horizontal: horizontal, vertical: vertical };
21
+ }
22
+ // ─── Tokens públicos ─────────────────────────────────────────────────────────
1
23
  export var Alignment = {
2
- // Horizontal only (para Column)
3
- Start: "flex-start",
4
- CenterHorizontally: "center",
5
- End: "flex-end",
6
- // Vertical only (para Row)
7
- Top: "flex-start",
8
- CenterVertically: "center",
9
- Bottom: "flex-end",
10
- // Compuestos (para Box y layouts avanzados)
11
- TopStart: "flex-start flex-start",
12
- TopCenter: "center flex-start",
13
- TopEnd: "flex-end flex-start",
14
- CenterStart: "flex-start center",
15
- Center: "center center",
16
- CenterEnd: "flex-end center",
17
- BottomStart: "flex-start flex-end",
18
- BottomCenter: "center flex-end",
19
- BottomEnd: "flex-end flex-end",
24
+ // Horizontal eje cross de Column
25
+ Start: h('flex-start'),
26
+ CenterHorizontally: h('center'),
27
+ End: h('flex-end'),
28
+ // Vertical eje cross de Row
29
+ Top: v('flex-start'),
30
+ CenterVertically: v('center'),
31
+ Bottom: v('flex-end'),
32
+ // Box alineación compuesta (stack)
33
+ TopStart: box('flex-start', 'flex-start'),
34
+ TopCenter: box('center', 'flex-start'),
35
+ TopEnd: box('flex-end', 'flex-start'),
36
+ CenterStart: box('flex-start', 'center'),
37
+ Center: box('center', 'center'),
38
+ CenterEnd: box('flex-end', 'center'),
39
+ BottomStart: box('flex-start', 'flex-end'),
40
+ BottomCenter: box('center', 'flex-end'),
41
+ BottomEnd: box('flex-end', 'flex-end'),
20
42
  };
@@ -1,23 +1,39 @@
1
1
  /**
2
- * Arrangement — eje principal (main axis)
3
- * Fiel a Jetpack Compose
2
+ * Arrangement — eje principal (main axis).
3
+ *
4
+ * Fiel a Jetpack Compose:
5
+ * - Arrangement.Start, Center, End, SpaceBetween, SpaceAround, SpaceEvenly
6
+ * - Arrangement.spacedBy(gap) → gap entre hijos, con justificación base opcional
7
+ * - Arrangement.spacedBy(gap, Arrangement.Center) → centrado + gap
4
8
  */
9
+ type JustifyContent = 'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around' | 'space-evenly';
5
10
  export type ArrangementValue = {
6
- type: "static";
7
- justifyContent: string;
11
+ readonly type: 'static';
12
+ readonly justifyContent: JustifyContent;
13
+ readonly gap?: never;
8
14
  } | {
9
- type: "spaced";
10
- gap: number;
11
- justifyContent: string;
15
+ readonly type: 'spaced';
16
+ readonly justifyContent: JustifyContent;
17
+ readonly gap: number;
12
18
  };
13
19
  export declare const Arrangement: {
20
+ readonly Top: ArrangementValue;
21
+ readonly Bottom: ArrangementValue;
14
22
  readonly Start: ArrangementValue;
15
- readonly Center: ArrangementValue;
16
23
  readonly End: ArrangementValue;
17
- readonly Bottom: ArrangementValue;
18
- readonly Top: ArrangementValue;
24
+ readonly Center: ArrangementValue;
19
25
  readonly SpaceBetween: ArrangementValue;
20
26
  readonly SpaceAround: ArrangementValue;
21
27
  readonly SpaceEvenly: ArrangementValue;
22
- readonly spacedBy: (value: number) => ArrangementValue;
28
+ /**
29
+ * Espaciado uniforme entre hijos con gap en px.
30
+ * @param gap Espacio en píxeles entre elementos
31
+ * @param baseAlign Alineación base del main-axis (por defecto flex-start)
32
+ *
33
+ * @example
34
+ * Arrangement.spacedBy(16)
35
+ * Arrangement.spacedBy(16, Arrangement.Center)
36
+ */
37
+ readonly spacedBy: (gap: number, baseAlign?: ArrangementValue) => ArrangementValue;
23
38
  };
39
+ export {};
@@ -1,46 +1,39 @@
1
1
  /**
2
- * Arrangement — eje principal (main axis)
3
- * Fiel a Jetpack Compose
2
+ * Arrangement — eje principal (main axis).
3
+ *
4
+ * Fiel a Jetpack Compose:
5
+ * - Arrangement.Start, Center, End, SpaceBetween, SpaceAround, SpaceEvenly
6
+ * - Arrangement.spacedBy(gap) → gap entre hijos, con justificación base opcional
7
+ * - Arrangement.spacedBy(gap, Arrangement.Center) → centrado + gap
4
8
  */
9
+ // ─── Tokens estáticos ────────────────────────────────────────────────────────
10
+ var staticArrangement = function (justifyContent) {
11
+ return ({ type: 'static', justifyContent: justifyContent });
12
+ };
13
+ // ─── Arrangement public API ──────────────────────────────────────────────────
5
14
  export var Arrangement = {
6
- // --- simples ---
7
- Start: {
8
- type: "static",
9
- justifyContent: "flex-start",
10
- },
11
- Center: {
12
- type: "static",
13
- justifyContent: "center",
14
- },
15
- End: {
16
- type: "static",
17
- justifyContent: "flex-end",
18
- },
19
- Bottom: {
20
- type: "static",
21
- justifyContent: "flex-end"
22
- },
23
- Top: {
24
- type: "static",
25
- justifyContent: "flex-start"
26
- },
27
- SpaceBetween: {
28
- type: "static",
29
- justifyContent: "space-between",
30
- },
31
- SpaceAround: {
32
- type: "static",
33
- justifyContent: "space-around",
34
- },
35
- SpaceEvenly: {
36
- type: "static",
37
- justifyContent: "space-evenly",
38
- },
39
- spacedBy: function (value) {
40
- return {
41
- type: "spaced",
42
- gap: value,
43
- justifyContent: "flex-start",
44
- };
15
+ // Column main-axis (vertical)
16
+ Top: staticArrangement('flex-start'),
17
+ Bottom: staticArrangement('flex-end'),
18
+ // Row main-axis (horizontal)
19
+ Start: staticArrangement('flex-start'),
20
+ End: staticArrangement('flex-end'),
21
+ // Compartidos
22
+ Center: staticArrangement('center'),
23
+ SpaceBetween: staticArrangement('space-between'),
24
+ SpaceAround: staticArrangement('space-around'),
25
+ SpaceEvenly: staticArrangement('space-evenly'),
26
+ /**
27
+ * Espaciado uniforme entre hijos con gap en px.
28
+ * @param gap Espacio en píxeles entre elementos
29
+ * @param baseAlign Alineación base del main-axis (por defecto flex-start)
30
+ *
31
+ * @example
32
+ * Arrangement.spacedBy(16)
33
+ * Arrangement.spacedBy(16, Arrangement.Center)
34
+ */
35
+ spacedBy: function (gap, baseAlign) {
36
+ if (baseAlign === void 0) { baseAlign = staticArrangement('flex-start'); }
37
+ return { type: 'spaced', gap: gap, justifyContent: baseAlign.justifyContent };
45
38
  },
46
39
  };
@@ -1,25 +1,54 @@
1
- <script lang="ts">
2
- import { Modifier } from "../../core/modifier/Modifier";
3
- import type {BoxAlignment} from "./Alignment";
4
-
5
- export let modifier: Modifier = Modifier.empty();
6
- export let contentAlignment: BoxAlignment | undefined = undefined;
7
-
8
- $: contentStyle = contentAlignment ? alignmentToFlexStyle(contentAlignment) : "";
9
-
10
- function alignmentToFlexStyle(alignment: BoxAlignment): string {
11
- const parts = alignment.split(" ");
12
- const horiz = parts[0] === "flex-start" ? "flex-start" : parts[0] === "flex-end" ? "flex-end" : "center";
13
- const vert = parts[1] || parts[0];
14
- const v = vert === "flex-start" ? "flex-start" : vert === "flex-end" ? "flex-end" : "center";
15
-
16
- return `display:flex; align-items:${v}; justify-content:${horiz};`;
17
- }
18
- </script>
19
-
20
- <div
21
- class="relative"
22
- style={`${contentStyle} ${modifier.toStyle()}`}
23
- >
24
- <slot />
25
- </div>
1
+ <script lang="ts">
2
+ import { Modifier } from "../../core/modifier/Modifier";
3
+ import { Alignment } from "./Alignment";
4
+ import type { BoxAlignment } from "./Alignment";
5
+ import { resolveBoxPlaceItems } from "./resolveAlignment";
6
+
7
+ export let modifier: Modifier = Modifier.empty();
8
+
9
+ /**
10
+ * Alineación por defecto para TODOS los hijos del Box.
11
+ * Equivalente a contentAlignment en Jetpack Compose.
12
+ *
13
+ * Cada hijo puede sobreescribir con Modifier.align(Alignment.XXX).
14
+ *
15
+ * @default Alignment.TopStart
16
+ */
17
+ export let contentAlignment: BoxAlignment = Alignment.TopStart;
18
+
19
+ /**
20
+ * CSS Grid place-items resuelto desde el contentAlignment.
21
+ * Formato: "<vertical> <horizontal>"
22
+ */
23
+ $: placeItems = resolveBoxPlaceItems(contentAlignment);
24
+ </script>
25
+
26
+ <!--
27
+ Box — contenedor de apilamiento (stack), fiel a Jetpack Compose.
28
+
29
+ Implementación:
30
+ • display: grid con grid-template-areas: 'stack'
31
+ • El CSS interno fuerza a todos los hijos directos a usar grid-area: 'stack'
32
+ • Esto hace que todos los hijos se solapen en la misma celda.
33
+ • place-items controla la alineación por defecto de TODOS los hijos.
34
+ • Cada hijo puede sobreescribir con place-self via Modifier.align().
35
+ -->
36
+ <div
37
+ class="cs-box"
38
+ style={`
39
+ display: grid;
40
+ grid-template-areas: 'stack';
41
+ place-items: ${placeItems};
42
+ position: relative;
43
+ ${modifier.toStyle()}
44
+ `}
45
+ >
46
+ <slot />
47
+ </div>
48
+
49
+ <style>
50
+ /* Fuerza a todos los hijos directos a apilarse en la misma área de grid */
51
+ .cs-box > :global(*) {
52
+ grid-area: stack;
53
+ }
54
+ </style>
@@ -20,7 +20,14 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
20
20
  } : {});
21
21
  declare const Box: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
22
22
  modifier?: Modifier;
23
- contentAlignment?: BoxAlignment | undefined;
23
+ /**
24
+ * Alineación por defecto para TODOS los hijos del Box.
25
+ * Equivalente a contentAlignment en Jetpack Compose.
26
+ *
27
+ * Cada hijo puede sobreescribir con Modifier.align(Alignment.XXX).
28
+ *
29
+ * @default Alignment.TopStart
30
+ */ contentAlignment?: BoxAlignment;
24
31
  }, {
25
32
  default: {};
26
33
  }>, {
@@ -1,23 +1,52 @@
1
- <script lang="ts">
2
- import { Modifier } from "../../core/modifier/Modifier";
3
- import { Alignment } from "./Alignment";
4
- import { Arrangement } from "./Arrangement";
5
- import type { ArrangementValue } from "./Arrangement";
6
- import type { HorizontalAlignment } from "./Alignment";
7
-
8
- export let modifier: Modifier = Modifier.empty();
9
- export let horizontalAlignment: HorizontalAlignment = Alignment.Start;
10
- export let verticalArrangement: ArrangementValue = Arrangement.Start;
11
- </script>
12
-
13
- <div
14
- class="flex flex-col"
15
- style={`
16
- align-items: ${horizontalAlignment};
17
- justify-content: ${verticalArrangement.justifyContent};
18
- ${verticalArrangement.type === "spaced" ? `gap:${verticalArrangement.gap}px;` : ""}
19
- ${modifier.toStyle()}
20
- `}
21
- >
22
- <slot />
23
- </div>
1
+ <script lang="ts">
2
+ import { Modifier } from "../../core/modifier/Modifier";
3
+ import { Alignment } from "./Alignment";
4
+ import { Arrangement } from "./Arrangement";
5
+ import type { ArrangementValue } from "./Arrangement";
6
+ import type { HorizontalAlignment } from "./Alignment";
7
+
8
+ export let modifier: Modifier = Modifier.empty();
9
+
10
+ /**
11
+ * Alineación en el eje cross (horizontal) de todos los hijos.
12
+ * Equivalente a horizontalAlignment en Jetpack Compose Column.
13
+ * @default Alignment.Start
14
+ */
15
+ export let horizontalAlignment: HorizontalAlignment = Alignment.Start;
16
+
17
+ /**
18
+ * Disposición en el eje main (vertical).
19
+ * Equivalente a verticalArrangement en Jetpack Compose Column.
20
+ * @default Arrangement.Top
21
+ */
22
+ export let verticalArrangement: ArrangementValue = Arrangement.Top;
23
+
24
+ $: gapStyle = verticalArrangement.type === 'spaced'
25
+ ? `gap:${verticalArrangement.gap}px;`
26
+ : '';
27
+ </script>
28
+
29
+ <!--
30
+ Column — contenedor flex vertical.
31
+
32
+ • align-items controla la alineación horizontal de los hijos (cross-axis)
33
+ • justify-content controla la distribución vertical (main-axis)
34
+ • Los hijos pueden sobreescribir su alineación individual via
35
+ Modifier.align() que inyecta align-self en su propio estilo
36
+
37
+ No hay wrapper interno: cada hijo gestiona su propio layout.
38
+ El scroll no está habilitado por defecto — usar Modifier.verticalScroll()
39
+ o LazyColumn para contenido que desborda.
40
+ -->
41
+ <div
42
+ style={`
43
+ display: flex;
44
+ flex-direction: column;
45
+ align-items: ${horizontalAlignment.cssValue};
46
+ justify-content: ${verticalArrangement.justifyContent};
47
+ ${gapStyle}
48
+ ${modifier.toStyle()}
49
+ `}
50
+ >
51
+ <slot />
52
+ </div>
@@ -21,8 +21,16 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
21
21
  } : {});
22
22
  declare const Column: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
23
23
  modifier?: Modifier;
24
- horizontalAlignment?: HorizontalAlignment;
25
- verticalArrangement?: ArrangementValue;
24
+ /**
25
+ * Alineación en el eje cross (horizontal) de todos los hijos.
26
+ * Equivalente a horizontalAlignment en Jetpack Compose Column.
27
+ * @default Alignment.Start
28
+ */ horizontalAlignment?: HorizontalAlignment;
29
+ /**
30
+ * Disposición en el eje main (vertical).
31
+ * Equivalente a verticalArrangement en Jetpack Compose Column.
32
+ * @default Arrangement.Top
33
+ */ verticalArrangement?: ArrangementValue;
26
34
  }, {
27
35
  default: {};
28
36
  }>, {
@@ -0,0 +1 @@
1
+ export type LayoutContext = "flex" | "box";
@@ -0,0 +1 @@
1
+ export {};
@@ -18,7 +18,7 @@
18
18
  let scrollTop = 0;
19
19
  let viewportHeight = 0;
20
20
 
21
- let estimatedItemHeight = 56; // fallback Material
21
+ let estimatedItemHeight = 56;
22
22
  let measured = false;
23
23
 
24
24
  const overscan = 3;
@@ -43,7 +43,7 @@
43
43
  scrollTop = (e.target as HTMLDivElement).scrollTop;
44
44
  }
45
45
 
46
- // --- Virtualization math ---
46
+ // --- Virtualization ---
47
47
  $: totalHeight = items.length * estimatedItemHeight;
48
48
 
49
49
  $: startIndex = Math.max(
@@ -55,13 +55,11 @@
55
55
  Math.ceil(viewportHeight / estimatedItemHeight) + overscan * 2;
56
56
 
57
57
  $: endIndex = Math.min(items.length, startIndex + visibleCount);
58
-
59
58
  $: visibleItems = items.slice(startIndex, endIndex);
60
59
 
61
- // --- Arrangement ---
62
- function resolveGap(arrangement: ArrangementValue): string {
63
- return arrangement.type === "spaced"
64
- ? `${arrangement.gap}px`
60
+ function resolveGap(): string {
61
+ return verticalArrangement.type === "spaced"
62
+ ? `${verticalArrangement.gap}px`
65
63
  : "0px";
66
64
  }
67
65
  </script>
@@ -69,15 +67,17 @@
69
67
  <div
70
68
  bind:this={container}
71
69
  on:scroll={onScroll}
70
+ class="compose-lazy-column"
72
71
  style={`
73
- overflow-y:auto;
74
- position:relative;
72
+ overflow-y: auto;
73
+ overflow-x: hidden;
74
+ position: relative;
75
75
  ${modifier.toStyle()}
76
76
  `}
77
77
  >
78
- <!-- Total scroll space -->
78
+ <!-- Espacio total -->
79
79
  <div style={`height:${totalHeight}px; position:relative;`}>
80
- <!-- Visible window -->
80
+ <!-- Ventana visible -->
81
81
  <div
82
82
  style={`
83
83
  position:absolute;
@@ -88,7 +88,7 @@
88
88
  display:flex;
89
89
  flex-direction:column;
90
90
  align-items:${horizontalAlignment};
91
- gap:${resolveGap(verticalArrangement)};
91
+ gap:${resolveGap()};
92
92
  `}
93
93
  >
94
94
  {#each visibleItems as item, i}
@@ -1,71 +1,107 @@
1
1
  <script lang="ts">
2
2
  import { Modifier } from "../../core/modifier/Modifier";
3
+ import { onMount, tick } from "svelte";
3
4
  import { Alignment } from "./Alignment";
4
5
  import { Arrangement } from "./Arrangement";
5
6
  import type { ArrangementValue } from "./Arrangement";
6
- import type { VerticalAlignment } from "./Alignment";
7
+ import type { HorizontalAlignment } from "./Alignment";
7
8
 
8
9
  export let items: any[] = [];
9
10
  export let modifier: Modifier = Modifier.empty();
10
11
 
11
- export let verticalAlignment: VerticalAlignment = Alignment.Top;
12
- export let horizontalArrangement: ArrangementValue = Arrangement.Start;
12
+ export let horizontalAlignment: HorizontalAlignment = Alignment.Start;
13
+ export let verticalArrangement: ArrangementValue = Arrangement.Start;
13
14
 
14
- export let scrollEnabled: boolean = true;
15
- export let hideScrollbar: boolean = false;
16
- export let horizontalSpacing: number | null = null;
15
+ let container: HTMLDivElement;
16
+ let probeItem: HTMLDivElement | null = null;
17
17
 
18
- function resolveGap(): string {
19
- if (horizontalSpacing !== null) {
20
- return `${horizontalSpacing}px`;
18
+ let scrollTop = 0;
19
+ let viewportHeight = 0;
20
+
21
+ let estimatedItemHeight = 56; // fallback Material
22
+ let measured = false;
23
+
24
+ const overscan = 3;
25
+
26
+ onMount(() => {
27
+ viewportHeight = container.clientHeight;
28
+ });
29
+
30
+ async function measure() {
31
+ await tick();
32
+ if (probeItem) {
33
+ estimatedItemHeight = probeItem.offsetHeight;
34
+ measured = true;
21
35
  }
36
+ }
22
37
 
23
- return horizontalArrangement.type === "spaced"
24
- ? `${horizontalArrangement.gap}px`
25
- : "0px";
38
+ $: if (probeItem && !measured) {
39
+ measure();
26
40
  }
27
41
 
28
- function resolveOverflowX(): string {
29
- return scrollEnabled ? "auto" : "hidden";
42
+ function onScroll(e: Event) {
43
+ scrollTop = (e.target as HTMLDivElement).scrollTop;
30
44
  }
31
45
 
32
- function resolveScrollbarStyle(): string {
33
- if (!hideScrollbar) return "";
46
+ // --- Virtualization math ---
47
+ $: totalHeight = items.length * estimatedItemHeight;
34
48
 
35
- return `
36
- scrollbar-width: none;
37
- -ms-overflow-style: none;
38
- `;
39
- }
40
- </script>
49
+ $: startIndex = Math.max(
50
+ 0,
51
+ Math.floor(scrollTop / estimatedItemHeight) - overscan
52
+ );
41
53
 
42
- <div
43
- class={hideScrollbar ? "lazy-row--hide-scrollbar" : ""}
44
- style={`
45
- display: flex;
46
- flex-direction: row;
54
+ $: visibleCount =
55
+ Math.ceil(viewportHeight / estimatedItemHeight) + overscan * 2;
47
56
 
48
- align-items: ${verticalAlignment};
49
- justify-content: ${horizontalArrangement.justifyContent};
50
- gap: ${resolveGap()};
57
+ $: endIndex = Math.min(items.length, startIndex + visibleCount);
51
58
 
52
- overflow-x: ${resolveOverflowX()};
53
- overflow-y: visible;
59
+ $: visibleItems = items.slice(startIndex, endIndex);
54
60
 
55
- height: fit-content;
56
- min-height: fit-content;
61
+ // --- Arrangement ---
62
+ function resolveGap(arrangement: ArrangementValue): string {
63
+ return arrangement.type === "spaced"
64
+ ? `${arrangement.gap}px`
65
+ : "0px";
66
+ }
67
+ </script>
57
68
 
58
- ${resolveScrollbarStyle()}
69
+ <div
70
+ bind:this={container}
71
+ on:scroll={onScroll}
72
+ style={`
73
+ overflow-y:auto;
74
+ position:relative;
59
75
  ${modifier.toStyle()}
60
76
  `}
61
77
  >
62
- {#each items as item}
63
- <slot {item} />
64
- {/each}
65
- </div>
66
-
67
- <style>
68
- .lazy-row--hide-scrollbar::-webkit-scrollbar {
69
- display: none;
70
- }
71
- </style>
78
+ <!-- Total scroll space -->
79
+ <div style={`height:${totalHeight}px; position:relative;`}>
80
+ <!-- Visible window -->
81
+ <div
82
+ style={`
83
+ position:absolute;
84
+ top:${startIndex * estimatedItemHeight}px;
85
+ left:0;
86
+ right:0;
87
+
88
+ display:flex;
89
+ flex-direction:column;
90
+ align-items:${horizontalAlignment};
91
+ gap:${resolveGap(verticalArrangement)};
92
+ `}
93
+ >
94
+ {#each visibleItems as item, i}
95
+ {#if i === 0 && !measured}
96
+ <div bind:this={probeItem}>
97
+ <slot {item} />
98
+ </div>
99
+ {:else}
100
+ <div>
101
+ <slot {item} />
102
+ </div>
103
+ {/if}
104
+ {/each}
105
+ </div>
106
+ </div>
107
+ </div>
@@ -1,6 +1,6 @@
1
1
  import { Modifier } from "../../core/modifier/Modifier";
2
2
  import type { ArrangementValue } from "./Arrangement";
3
- import type { VerticalAlignment } from "./Alignment";
3
+ import type { HorizontalAlignment } from "./Alignment";
4
4
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
5
5
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
6
  $$bindings?: Bindings;
@@ -22,11 +22,8 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
22
22
  declare const LazyRow: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
23
23
  items?: any[];
24
24
  modifier?: Modifier;
25
- verticalAlignment?: VerticalAlignment;
26
- horizontalArrangement?: ArrangementValue;
27
- scrollEnabled?: boolean;
28
- hideScrollbar?: boolean;
29
- horizontalSpacing?: number | null;
25
+ horizontalAlignment?: HorizontalAlignment;
26
+ verticalArrangement?: ArrangementValue;
30
27
  }, {
31
28
  default: {
32
29
  item: any;