entasis 0.13.5 → 0.13.7

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 (76) hide show
  1. package/dist/components/Address/Address.svelte +44 -0
  2. package/dist/components/Address/Address.svelte.d.ts +4 -0
  3. package/dist/components/Address/address.d.ts +99 -0
  4. package/dist/components/Address/address.google.d.ts +89 -0
  5. package/dist/components/Address/address.google.fixtures.json +808 -0
  6. package/dist/components/Address/address.google.js +184 -0
  7. package/dist/components/Address/address.js +109 -0
  8. package/dist/components/Address/address.mcp.d.ts +1 -0
  9. package/dist/components/Address/address.mcp.js +100 -0
  10. package/dist/components/Address/address.props.d.ts +26 -0
  11. package/dist/components/Address/address.props.js +1 -0
  12. package/dist/components/Address/address.provider.d.ts +19 -0
  13. package/dist/components/Address/address.provider.js +69 -0
  14. package/dist/components/Address/address.theme.d.ts +63 -0
  15. package/dist/components/Address/address.theme.js +42 -0
  16. package/dist/components/Address/index.d.ts +6 -0
  17. package/dist/components/Address/index.js +5 -0
  18. package/dist/components/Form/AddressInput/AddressInput.svelte +482 -0
  19. package/dist/components/Form/AddressInput/AddressInput.svelte.d.ts +4 -0
  20. package/dist/components/Form/AddressInput/addressInput.mcp.d.ts +1 -0
  21. package/dist/components/Form/AddressInput/addressInput.mcp.js +110 -0
  22. package/dist/components/Form/AddressInput/addressInput.props.d.ts +72 -0
  23. package/dist/components/Form/AddressInput/addressInput.props.js +1 -0
  24. package/dist/components/Form/AddressInput/addressInput.theme.d.ts +63 -0
  25. package/dist/components/Form/AddressInput/addressInput.theme.js +55 -0
  26. package/dist/components/Form/AddressInput/index.d.ts +3 -0
  27. package/dist/components/Form/AddressInput/index.js +2 -0
  28. package/dist/components/Form/Field/field.d.ts +5 -2
  29. package/dist/components/Form/Field/field.state.svelte.js +4 -0
  30. package/dist/components/Form/Field/index.d.ts +1 -1
  31. package/dist/components/Form/Field/schemas.js +8 -0
  32. package/dist/components/Form/Form/FormInputRenderer.svelte +6 -0
  33. package/dist/components/Form/Form/form.d.ts +6 -0
  34. package/dist/components/Form/Form/form.mcp.d.ts +1 -1
  35. package/dist/components/Form/Form/form.mcp.js +1 -1
  36. package/dist/components/Form/Form/form.state.svelte.d.ts +142 -11
  37. package/dist/components/Form/Form/form.state.svelte.js +2 -0
  38. package/dist/components/Form/Form/visibility.d.ts +186 -20
  39. package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.d.ts +136 -0
  40. package/dist/components/Form/SignatureInput/SignatureInput.svelte +327 -0
  41. package/dist/components/Form/SignatureInput/SignatureInput.svelte.d.ts +4 -0
  42. package/dist/components/Form/SignatureInput/index.d.ts +4 -0
  43. package/dist/components/Form/SignatureInput/index.js +2 -0
  44. package/dist/components/Form/SignatureInput/signatureInput.mcp.d.ts +1 -0
  45. package/dist/components/Form/SignatureInput/signatureInput.mcp.js +74 -0
  46. package/dist/components/Form/SignatureInput/signatureInput.props.d.ts +29 -0
  47. package/dist/components/Form/SignatureInput/signatureInput.props.js +1 -0
  48. package/dist/components/Form/SignatureInput/signatureInput.strokes.d.ts +77 -0
  49. package/dist/components/Form/SignatureInput/signatureInput.strokes.js +149 -0
  50. package/dist/components/Form/SignatureInput/signatureInput.theme.d.ts +99 -0
  51. package/dist/components/Form/SignatureInput/signatureInput.theme.js +70 -0
  52. package/dist/components/Sidebar/Sidebar.svelte +1 -1
  53. package/dist/components/Sidebar/SidebarMenuItem.svelte +59 -15
  54. package/dist/components/Sidebar/SidebarMenuSubItem.svelte +43 -12
  55. package/dist/components/Sidebar/SidebarMenuText.svelte +60 -0
  56. package/dist/components/Sidebar/SidebarMenuText.svelte.d.ts +18 -0
  57. package/dist/components/Sidebar/sidebar.mcp.d.ts +1 -1
  58. package/dist/components/Sidebar/sidebar.mcp.js +53 -0
  59. package/dist/components/Sidebar/sidebar.props.d.ts +31 -0
  60. package/dist/components/Sidebar/sidebar.theme.d.ts +99 -0
  61. package/dist/components/Sidebar/sidebar.theme.js +100 -9
  62. package/dist/generated/componentAliases.d.ts +3 -0
  63. package/dist/generated/componentAliases.js +3 -0
  64. package/dist/generated/componentContract.d.ts +46 -1
  65. package/dist/generated/componentContract.js +113 -0
  66. package/dist/generated/componentMcpRegistry.js +6 -0
  67. package/dist/i18n/ar.js +18 -0
  68. package/dist/i18n/de.js +18 -0
  69. package/dist/i18n/en.d.ts +18 -0
  70. package/dist/i18n/en.js +18 -0
  71. package/dist/i18n/es.js +18 -0
  72. package/dist/i18n/fr.js +18 -0
  73. package/dist/i18n/ja.js +18 -0
  74. package/dist/i18n/pt.js +18 -0
  75. package/dist/i18n/zh.js +18 -0
  76. package/package.json +25 -1
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Strokes of a signature and the images they export to. Pure geometry: no DOM except the
3
+ * canvas context a caller passes in, so it runs the same in a test, on the pad and on export.
4
+ */
5
+ /** One sampled pointer position, in CSS pixels of the pad. */
6
+ export type SignaturePoint = {
7
+ x: number;
8
+ y: number;
9
+ /** Pen pressure from 0 to 1. Mouse and touch report 0.5. */
10
+ pressure: number;
11
+ };
12
+ /** One continuous line, from a pointer down to its pointer up. */
13
+ export type SignatureStroke = readonly SignaturePoint[];
14
+ export type SignatureBounds = {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ };
20
+ /** Exported image format: a PNG or an SVG, each as a data URL. */
21
+ export type SignatureFormat = 'png' | 'svg';
22
+ export type SignatureRenderOptions = {
23
+ /** CSS color of the ink. */
24
+ color: string;
25
+ /** Base line width in CSS pixels, at a pressure of 0.5. */
26
+ width: number;
27
+ };
28
+ /** Width of a segment drawn at `pressure`: half the base at no pressure, 1.5 times at full. */
29
+ export declare const strokeWidthAt: (pressure: number, width: number) => number;
30
+ /**
31
+ * The segments a stroke is drawn as: quadratic curves through the midpoints of its samples, so
32
+ * the line is smooth however coarse the pointer events were. Each segment carries the pressure it
33
+ * is drawn at, so a pen's line thickens and thins along the way.
34
+ */
35
+ export declare function strokeSegments(stroke: SignatureStroke): {
36
+ from: SignaturePoint;
37
+ control: SignaturePoint;
38
+ to: SignaturePoint;
39
+ pressure: number;
40
+ }[];
41
+ /** Draws `strokes` on a 2D context already scaled to CSS pixels. A tap draws a dot. */
42
+ export declare function drawStrokes(context: CanvasRenderingContext2D, strokes: readonly SignatureStroke[], { color, width }: SignatureRenderOptions): void;
43
+ /** The box the ink covers, line width included, or null when there is no ink. */
44
+ export declare function strokesBounds(strokes: readonly SignatureStroke[], width: number): SignatureBounds | null;
45
+ /** One drawable piece of a stroke: a dot for a tap, or a path at one line width. */
46
+ export type SignatureShape = {
47
+ kind: 'dot';
48
+ x: number;
49
+ y: number;
50
+ r: number;
51
+ } | {
52
+ kind: 'path';
53
+ d: string;
54
+ width: number;
55
+ };
56
+ /**
57
+ * The shapes a stroke draws as, in SVG path syntax, shifted by `offset`. Consecutive segments
58
+ * at the same width share one path, so a mouse or finger stroke is a single path and only a
59
+ * pen's changing pressure splits it.
60
+ */
61
+ export declare function strokeShapes(stroke: SignatureStroke, width: number, offset?: {
62
+ x: number;
63
+ y: number;
64
+ }): SignatureShape[];
65
+ /** A standalone SVG of the strokes, cropped to the ink plus `padding`. */
66
+ export declare function strokesToSvg(strokes: readonly SignatureStroke[], { color, width, padding }: SignatureRenderOptions & {
67
+ padding: number;
68
+ }): string | null;
69
+ /**
70
+ * Exports the strokes as a data URL cropped to the ink plus `padding`: an SVG, or a PNG drawn at
71
+ * `scale` device pixels per CSS pixel so it stays sharp in a document. Null when there is no ink.
72
+ */
73
+ export declare function exportStrokes(strokes: readonly SignatureStroke[], { format, color, width, padding, scale }: SignatureRenderOptions & {
74
+ format: SignatureFormat;
75
+ padding: number;
76
+ scale: number;
77
+ }): string | null;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Strokes of a signature and the images they export to. Pure geometry: no DOM except the
3
+ * canvas context a caller passes in, so it runs the same in a test, on the pad and on export.
4
+ */
5
+ /** Width of a segment drawn at `pressure`: half the base at no pressure, 1.5 times at full. */
6
+ export const strokeWidthAt = (pressure, width) => width * (0.5 + Math.min(Math.max(pressure, 0), 1));
7
+ const midpoint = (a, b) => ({
8
+ x: (a.x + b.x) / 2,
9
+ y: (a.y + b.y) / 2,
10
+ pressure: (a.pressure + b.pressure) / 2
11
+ });
12
+ /**
13
+ * The segments a stroke is drawn as: quadratic curves through the midpoints of its samples, so
14
+ * the line is smooth however coarse the pointer events were. Each segment carries the pressure it
15
+ * is drawn at, so a pen's line thickens and thins along the way.
16
+ */
17
+ export function strokeSegments(stroke) {
18
+ const segments = [];
19
+ if (stroke.length < 2)
20
+ return segments;
21
+ let from = stroke[0];
22
+ for (let index = 1; index < stroke.length - 1; index++) {
23
+ const control = stroke[index];
24
+ const to = midpoint(control, stroke[index + 1]);
25
+ segments.push({ from, control, to, pressure: control.pressure });
26
+ from = to;
27
+ }
28
+ const last = stroke[stroke.length - 1];
29
+ segments.push({ from, control: last, to: last, pressure: last.pressure });
30
+ return segments;
31
+ }
32
+ /** Draws `strokes` on a 2D context already scaled to CSS pixels. A tap draws a dot. */
33
+ export function drawStrokes(context, strokes, { color, width }) {
34
+ context.save();
35
+ context.strokeStyle = color;
36
+ context.fillStyle = color;
37
+ context.lineCap = 'round';
38
+ context.lineJoin = 'round';
39
+ for (const stroke of strokes) {
40
+ if (stroke.length === 1) {
41
+ const [dot] = stroke;
42
+ context.beginPath();
43
+ context.arc(dot.x, dot.y, strokeWidthAt(dot.pressure, width) / 2, 0, Math.PI * 2);
44
+ context.fill();
45
+ continue;
46
+ }
47
+ for (const segment of strokeSegments(stroke)) {
48
+ context.beginPath();
49
+ context.lineWidth = strokeWidthAt(segment.pressure, width);
50
+ context.moveTo(segment.from.x, segment.from.y);
51
+ context.quadraticCurveTo(segment.control.x, segment.control.y, segment.to.x, segment.to.y);
52
+ context.stroke();
53
+ }
54
+ }
55
+ context.restore();
56
+ }
57
+ /** The box the ink covers, line width included, or null when there is no ink. */
58
+ export function strokesBounds(strokes, width) {
59
+ let minX = Infinity;
60
+ let minY = Infinity;
61
+ let maxX = -Infinity;
62
+ let maxY = -Infinity;
63
+ for (const stroke of strokes) {
64
+ for (const point of stroke) {
65
+ const half = strokeWidthAt(point.pressure, width) / 2;
66
+ minX = Math.min(minX, point.x - half);
67
+ minY = Math.min(minY, point.y - half);
68
+ maxX = Math.max(maxX, point.x + half);
69
+ maxY = Math.max(maxY, point.y + half);
70
+ }
71
+ }
72
+ if (minX === Infinity)
73
+ return null;
74
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
75
+ }
76
+ const round = (value) => Math.round(value * 100) / 100;
77
+ /**
78
+ * The shapes a stroke draws as, in SVG path syntax, shifted by `offset`. Consecutive segments
79
+ * at the same width share one path, so a mouse or finger stroke is a single path and only a
80
+ * pen's changing pressure splits it.
81
+ */
82
+ export function strokeShapes(stroke, width, offset = { x: 0, y: 0 }) {
83
+ const x = (value) => round(value - offset.x);
84
+ const y = (value) => round(value - offset.y);
85
+ if (stroke.length === 1) {
86
+ const [dot] = stroke;
87
+ return [
88
+ { kind: 'dot', x: x(dot.x), y: y(dot.y), r: round(strokeWidthAt(dot.pressure, width) / 2) }
89
+ ];
90
+ }
91
+ const shapes = [];
92
+ for (const segment of strokeSegments(stroke)) {
93
+ const segmentWidth = round(strokeWidthAt(segment.pressure, width));
94
+ const curve = `Q${x(segment.control.x)} ${y(segment.control.y)} ${x(segment.to.x)} ${y(segment.to.y)}`;
95
+ const last = shapes.at(-1);
96
+ if (last?.kind === 'path' && last.width === segmentWidth)
97
+ last.d += curve;
98
+ else
99
+ shapes.push({
100
+ kind: 'path',
101
+ d: `M${x(segment.from.x)} ${y(segment.from.y)}${curve}`,
102
+ width: segmentWidth
103
+ });
104
+ }
105
+ return shapes;
106
+ }
107
+ /** A standalone SVG of the strokes, cropped to the ink plus `padding`. */
108
+ export function strokesToSvg(strokes, { color, width, padding }) {
109
+ const bounds = strokesBounds(strokes, width);
110
+ if (!bounds)
111
+ return null;
112
+ const offset = { x: bounds.x - padding, y: bounds.y - padding };
113
+ const boxWidth = round(bounds.width + padding * 2);
114
+ const boxHeight = round(bounds.height + padding * 2);
115
+ const shapes = strokes
116
+ .flatMap((stroke) => strokeShapes(stroke, width, offset))
117
+ .map((shape) => shape.kind === 'dot'
118
+ ? `<circle cx="${shape.x}" cy="${shape.y}" r="${shape.r}" fill="${color}"/>`
119
+ : `<path d="${shape.d}" stroke-width="${shape.width}"/>`);
120
+ return [
121
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${boxWidth}" height="${boxHeight}" viewBox="0 0 ${boxWidth} ${boxHeight}">`,
122
+ `<g fill="none" stroke="${color}" stroke-linecap="round" stroke-linejoin="round">`,
123
+ shapes.join(''),
124
+ '</g></svg>'
125
+ ].join('');
126
+ }
127
+ /**
128
+ * Exports the strokes as a data URL cropped to the ink plus `padding`: an SVG, or a PNG drawn at
129
+ * `scale` device pixels per CSS pixel so it stays sharp in a document. Null when there is no ink.
130
+ */
131
+ export function exportStrokes(strokes, { format, color, width, padding, scale }) {
132
+ if (format === 'svg') {
133
+ const svg = strokesToSvg(strokes, { color, width, padding });
134
+ return svg ? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}` : null;
135
+ }
136
+ const bounds = strokesBounds(strokes, width);
137
+ if (!bounds || typeof document === 'undefined')
138
+ return null;
139
+ const canvas = document.createElement('canvas');
140
+ canvas.width = Math.ceil((bounds.width + padding * 2) * scale);
141
+ canvas.height = Math.ceil((bounds.height + padding * 2) * scale);
142
+ const context = canvas.getContext('2d');
143
+ if (!context)
144
+ return null;
145
+ context.scale(scale, scale);
146
+ context.translate(padding - bounds.x, padding - bounds.y);
147
+ drawStrokes(context, strokes, { color, width });
148
+ return canvas.toDataURL('image/png');
149
+ }
@@ -0,0 +1,99 @@
1
+ import { type InferComponentTheme } from '../../../utils/cva/index.js';
2
+ export declare const signatureInputTheme: {
3
+ frame: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
4
+ pad: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
5
+ size: {
6
+ small: string;
7
+ normal: string;
8
+ large: string;
9
+ };
10
+ interactive: {
11
+ true: string;
12
+ false: string;
13
+ };
14
+ disabled: {
15
+ true: string;
16
+ false: string;
17
+ };
18
+ hasError: {
19
+ true: string;
20
+ false: string;
21
+ };
22
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
23
+ ink: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
24
+ image: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
25
+ placeholder: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
26
+ size: {
27
+ small: string;
28
+ normal: string;
29
+ large: string;
30
+ };
31
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
32
+ actions: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
33
+ };
34
+ export type SignatureInputTheme = typeof signatureInputTheme;
35
+ export type SignatureInputThemeProps = InferComponentTheme<SignatureInputTheme>;
36
+ export declare const setSignatureInputTheme: (theme: InferComponentTheme<{
37
+ frame: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
38
+ pad: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
39
+ size: {
40
+ small: string;
41
+ normal: string;
42
+ large: string;
43
+ };
44
+ interactive: {
45
+ true: string;
46
+ false: string;
47
+ };
48
+ disabled: {
49
+ true: string;
50
+ false: string;
51
+ };
52
+ hasError: {
53
+ true: string;
54
+ false: string;
55
+ };
56
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
57
+ ink: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
58
+ image: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
59
+ placeholder: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
60
+ size: {
61
+ small: string;
62
+ normal: string;
63
+ large: string;
64
+ };
65
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
66
+ actions: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
67
+ }>) => void;
68
+ export declare const useSignatureInputTheme: import("../../../utils/cva/theme.ts").UseComponentTheme<{
69
+ frame: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
70
+ pad: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
71
+ size: {
72
+ small: string;
73
+ normal: string;
74
+ large: string;
75
+ };
76
+ interactive: {
77
+ true: string;
78
+ false: string;
79
+ };
80
+ disabled: {
81
+ true: string;
82
+ false: string;
83
+ };
84
+ hasError: {
85
+ true: string;
86
+ false: string;
87
+ };
88
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
89
+ ink: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
90
+ image: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
91
+ placeholder: (props?: (import("../../../utils/cva/types.ts").CVAVariantSchema<{
92
+ size: {
93
+ small: string;
94
+ normal: string;
95
+ large: string;
96
+ };
97
+ }> & import("../../../utils/cva/types.ts").CVAClassProp) | undefined) => string;
98
+ actions: (props?: import("../../../utils/cva/types.ts").CVAClassProp | undefined) => string;
99
+ }>;
@@ -0,0 +1,70 @@
1
+ import { cva, setComponentTheme, useComponentTheme } from '../../../utils/cva/index.js';
2
+ // Holds the pad and, over its corner, the buttons: they cannot sit inside the pad, whose image
3
+ // role would hide them from assistive technology.
4
+ const defaultFrame = cva({
5
+ base: 'relative w-full min-w-0'
6
+ });
7
+ // The pad is the control: it takes focus, so its own ring shows keyboard focus, and the strokes
8
+ // are drawn in its text color (an SVG in `currentColor`), so they follow the theme.
9
+ const defaultPad = cva({
10
+ base: 'relative w-full min-w-0 touch-none overflow-hidden rounded-md border border-neutral-muted bg-surface-raised text-neutral outline-none select-none focus-visible:ring-2 focus-visible:ring-focus/50',
11
+ variants: {
12
+ size: {
13
+ small: 'h-28',
14
+ normal: 'h-36',
15
+ large: 'h-44'
16
+ },
17
+ interactive: {
18
+ true: 'cursor-crosshair',
19
+ false: ''
20
+ },
21
+ disabled: {
22
+ true: 'cursor-not-allowed opacity-50',
23
+ false: ''
24
+ },
25
+ hasError: {
26
+ true: 'border-danger focus-visible:ring-danger/50',
27
+ false: ''
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ size: 'normal',
32
+ interactive: true,
33
+ disabled: false,
34
+ hasError: false
35
+ }
36
+ });
37
+ const defaultInk = cva({
38
+ base: 'pointer-events-none absolute inset-0 size-full overflow-visible'
39
+ });
40
+ // A value set from outside (a saved signature) shows as an image, scaled to fit the pad.
41
+ const defaultImage = cva({
42
+ base: 'pointer-events-none absolute inset-0 size-full object-contain p-md'
43
+ });
44
+ // The line to sign on and its hint: decorative, gone as soon as there is ink.
45
+ const defaultPlaceholder = cva({
46
+ base: 'pointer-events-none absolute inset-x-[var(--space-xl)] bottom-1/4 flex items-end gap-sm border-b border-dashed border-neutral-muted pb-xs text-neutral/45',
47
+ variants: {
48
+ size: {
49
+ small: 'text-xs',
50
+ normal: 'text-sm',
51
+ large: 'text-base'
52
+ }
53
+ },
54
+ defaultVariants: {
55
+ size: 'normal'
56
+ }
57
+ });
58
+ const defaultActions = cva({
59
+ base: 'absolute end-[var(--space-xs)] top-[var(--space-xs)] flex items-center gap-xs'
60
+ });
61
+ export const signatureInputTheme = {
62
+ frame: defaultFrame,
63
+ pad: defaultPad,
64
+ ink: defaultInk,
65
+ image: defaultImage,
66
+ placeholder: defaultPlaceholder,
67
+ actions: defaultActions
68
+ };
69
+ export const setSignatureInputTheme = setComponentTheme('signature-input');
70
+ export const useSignatureInputTheme = useComponentTheme('signature-input', signatureInputTheme);
@@ -266,7 +266,7 @@
266
266
  });
267
267
 
268
268
  function hasIcon(entry: SidebarMenuEntry) {
269
- return entry.icon != null;
269
+ return entry.icon != null || entry.media != null;
270
270
  }
271
271
 
272
272
  function hasCollapsibleMedia(button: SidebarMenuButtonItem | undefined) {
@@ -28,6 +28,7 @@
28
28
  import SidebarFlyout from './SidebarFlyout.svelte';
29
29
  import SidebarIcon from './SidebarIcon.svelte';
30
30
  import SidebarMenuSubItem from './SidebarMenuSubItem.svelte';
31
+ import SidebarMenuText from './SidebarMenuText.svelte';
31
32
  import { useSidebarSuffixWidth } from './sidebar.suffix.svelte.js';
32
33
  import { useSidebarMotion, useSidebarTheme, type SidebarThemeProps } from './sidebar.theme.js';
33
34
 
@@ -82,6 +83,13 @@
82
83
  );
83
84
  const hasSubmenu = $derived(!!item.items?.length);
84
85
  const showBadge = $derived(item.badge != null && !isIconCollapsed);
86
+ // A description stacks a second line under the label, so the row takes the large height
87
+ // unless the entry sets its own size.
88
+ const rowSize = $derived(item.size ?? (item.description != null ? 'large' : undefined));
89
+ const lead = $derived(item.media ? 'media' : 'icon');
90
+ // On a two-line row the suffix and the badge sit on the description's line, so the label's
91
+ // line, and its meta, run to the same end on every row.
92
+ const twoLine = $derived(item.description != null);
85
93
  // An in-flow chevron or dots after the badge: the row then keeps its action's room at every
86
94
  // width, since the action would otherwise cover that glyph when it shows.
87
95
  const hasTrailingGlyph = $derived(
@@ -94,8 +102,12 @@
94
102
  const endReserve = $derived(
95
103
  item.suffix
96
104
  ? item.action
97
- ? 'suffixAction'
98
- : 'suffix'
105
+ ? twoLine
106
+ ? 'suffixLineAction'
107
+ : 'suffixAction'
108
+ : twoLine
109
+ ? 'suffixLine'
110
+ : 'suffix'
99
111
  : !item.action
100
112
  ? 'none'
101
113
  : showBadge && !hasTrailingGlyph
@@ -176,7 +188,11 @@
176
188
  </script>
177
189
 
178
190
  {#snippet entryContent()}
179
- {#if hasIconSurface}
191
+ {#if item.media}
192
+ <span data-slot="sidebar-menu-media" data-sidebar="menu-media" class={classes.menuMedia()}>
193
+ {@render item.media(api, item)}
194
+ </span>
195
+ {:else if hasIconSurface}
180
196
  <span
181
197
  data-slot="sidebar-menu-icon"
182
198
  data-color={item.iconColor}
@@ -187,7 +203,25 @@
187
203
  {:else}
188
204
  <SidebarIcon icon={item.icon} class={back ? 'rtl:-scale-x-100' : undefined} />
189
205
  {/if}
190
- <span class={classes.menuLabel()}>{item.label}</span>
206
+ {#if item.description != null || item.meta != null}
207
+ <SidebarMenuText
208
+ label={item.label}
209
+ description={item.description}
210
+ meta={isIconCollapsed ? undefined : item.meta}
211
+ suffix={!!item.suffix}
212
+ trailing={twoLine ? badge : undefined}
213
+ {size}
214
+ {theme}
215
+ />
216
+ {:else}
217
+ <span class={classes.menuLabel()}>{item.label}</span>
218
+ {/if}
219
+ {#if !twoLine}
220
+ {@render badge()}
221
+ {/if}
222
+ {/snippet}
223
+
224
+ {#snippet badge()}
191
225
  {#if showBadge}
192
226
  <span
193
227
  data-slot="sidebar-menu-badge"
@@ -224,7 +258,7 @@
224
258
  role={item.disabled ? 'link' : undefined}
225
259
  data-slot="sidebar-menu-button"
226
260
  data-sidebar="menu-button"
227
- data-size={item.size ?? 'normal'}
261
+ data-size={rowSize ?? 'normal'}
228
262
  data-active={item.isActive ? 'true' : undefined}
229
263
  data-active-variant={activeVariant}
230
264
  aria-current={item.isActive ? 'page' : undefined}
@@ -236,7 +270,8 @@
236
270
  activeVariant,
237
271
  size,
238
272
  density,
239
- itemSize: item.size,
273
+ itemSize: rowSize,
274
+ lead,
240
275
  endReserve,
241
276
  className: item.class
242
277
  })}
@@ -254,7 +289,7 @@
254
289
  type="button"
255
290
  data-slot="sidebar-menu-button"
256
291
  data-sidebar="menu-button"
257
- data-size={item.size ?? 'normal'}
292
+ data-size={rowSize ?? 'normal'}
258
293
  data-active={item.isActive ? 'true' : undefined}
259
294
  data-active-variant={activeVariant}
260
295
  aria-current={item.isActive ? 'page' : undefined}
@@ -267,7 +302,8 @@
267
302
  activeVariant,
268
303
  size,
269
304
  density,
270
- itemSize: item.size,
305
+ itemSize: rowSize,
306
+ lead,
271
307
  endReserve,
272
308
  className: item.class
273
309
  })}
@@ -302,7 +338,7 @@
302
338
  type="button"
303
339
  data-slot="sidebar-menu-button"
304
340
  data-sidebar="menu-button"
305
- data-size={item.size ?? 'normal'}
341
+ data-size={rowSize ?? 'normal'}
306
342
  data-active-variant={activeVariant}
307
343
  disabled={item.disabled || undefined}
308
344
  class={classes.menuButton({
@@ -310,7 +346,8 @@
310
346
  activeVariant,
311
347
  size,
312
348
  density,
313
- itemSize: item.size,
349
+ itemSize: rowSize,
350
+ lead,
314
351
  endReserve,
315
352
  className: ['aria-expanded:bg-neutral-muted', item.class]
316
353
  })}
@@ -339,7 +376,7 @@
339
376
  type="button"
340
377
  data-slot="sidebar-menu-button"
341
378
  data-sidebar="menu-button"
342
- data-size={item.size ?? 'normal'}
379
+ data-size={rowSize ?? 'normal'}
343
380
  data-active={item.isActive ? 'true' : undefined}
344
381
  data-active-variant={activeVariant}
345
382
  class={classes.menuButton({
@@ -347,7 +384,8 @@
347
384
  activeVariant,
348
385
  size,
349
386
  density,
350
- itemSize: item.size,
387
+ itemSize: rowSize,
388
+ lead,
351
389
  endReserve,
352
390
  className: item.class
353
391
  })}
@@ -434,7 +472,7 @@
434
472
  type="button"
435
473
  data-slot="sidebar-menu-button"
436
474
  data-sidebar="menu-button"
437
- data-size={item.size ?? 'normal'}
475
+ data-size={rowSize ?? 'normal'}
438
476
  data-active={item.isActive ? 'true' : undefined}
439
477
  data-active-variant={activeVariant}
440
478
  disabled={item.disabled || undefined}
@@ -443,7 +481,8 @@
443
481
  activeVariant,
444
482
  size,
445
483
  density,
446
- itemSize: item.size,
484
+ itemSize: rowSize,
485
+ lead,
447
486
  endReserve,
448
487
  className: item.class
449
488
  })}
@@ -473,7 +512,12 @@
473
512
  data-sidebar="menu-suffix"
474
513
  inert={isIconCollapsed ? true : undefined}
475
514
  aria-hidden={isIconCollapsed ? 'true' : undefined}
476
- class={classes.suffix({ size, density, action: item.action ? 'action' : 'none' })}
515
+ class={classes.suffix({
516
+ size,
517
+ density,
518
+ action: item.action ? 'action' : 'none',
519
+ line: twoLine ? 'two' : 'one'
520
+ })}
477
521
  {@attach suffixWidth.measure}
478
522
  >
479
523
  {@render item.suffix(api, item)}