pika-ux 1.0.0-beta.9 → 1.0.1

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 (52) hide show
  1. package/dist/cli/template-files/pnpm-workspace.yaml +3 -3
  2. package/dist/cli/template-files/src/App.svelte +1 -1
  3. package/package.json +8 -1
  4. package/src/.DS_Store +0 -0
  5. package/src/App.svelte +2 -4
  6. package/src/icons/lucide/index.d.ts +28 -0
  7. package/src/pika/confirm-dialog/confirm-dialog.svelte +1 -1
  8. package/src/pika/pika-table/pika-table-pagination.svelte +32 -25
  9. package/src/pika/pika-table/pika-table-row-actions.svelte +1 -1
  10. package/src/pika/pika-table/pika-table.svelte +84 -58
  11. package/src/pika/pika-table/types.ts +13 -3
  12. package/src/pika/pika-toggle/index.ts +13 -0
  13. package/src/pika/pika-toggle/toggle.svelte +52 -0
  14. package/src/pika/pika-toggle-group/index.ts +10 -0
  15. package/src/pika/pika-toggle-group/toggle-group-item.svelte +88 -0
  16. package/src/pika/pika-toggle-group/toggle-group.svelte +72 -0
  17. package/src/pika/popup-help/popup-help.svelte +9 -3
  18. package/src/shadcn/chart/chart-container.svelte +69 -0
  19. package/src/shadcn/chart/chart-style.svelte +28 -0
  20. package/src/shadcn/chart/chart-tooltip.svelte +126 -0
  21. package/src/shadcn/chart/chart-utils.ts +37 -0
  22. package/src/shadcn/chart/index.ts +4 -0
  23. package/src/shadcn/dropdown-menu/dropdown-menu-group.svelte +2 -3
  24. package/src/shadcn/dropdown-menu/dropdown-menu-item.svelte +1 -1
  25. package/src/shadcn/dropdown-menu/dropdown-menu-label.svelte +1 -7
  26. package/src/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte +3 -13
  27. package/src/shadcn/dropdown-menu/dropdown-menu-radio-item.svelte +0 -1
  28. package/src/shadcn/dropdown-menu/dropdown-menu-separator.svelte +1 -7
  29. package/src/shadcn/dropdown-menu/dropdown-menu-shortcut.svelte +2 -13
  30. package/src/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +0 -1
  31. package/src/shadcn/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -2
  32. package/src/shadcn/dropdown-menu/dropdown-menu-trigger.svelte +2 -3
  33. package/src/shadcn/dropdown-menu/index.ts +44 -45
  34. package/src/shadcn/dropdown-menu copy/dropdown-menu-checkbox-item.svelte +41 -0
  35. package/src/shadcn/dropdown-menu copy/dropdown-menu-content.svelte +27 -0
  36. package/src/shadcn/dropdown-menu copy/dropdown-menu-group-heading.svelte +22 -0
  37. package/src/shadcn/dropdown-menu copy/dropdown-menu-group.svelte +7 -0
  38. package/src/shadcn/dropdown-menu copy/dropdown-menu-item.svelte +27 -0
  39. package/src/shadcn/dropdown-menu copy/dropdown-menu-label.svelte +24 -0
  40. package/src/shadcn/dropdown-menu copy/dropdown-menu-radio-group.svelte +16 -0
  41. package/src/shadcn/dropdown-menu copy/dropdown-menu-radio-item.svelte +26 -0
  42. package/src/shadcn/dropdown-menu copy/dropdown-menu-separator.svelte +13 -0
  43. package/src/shadcn/dropdown-menu copy/dropdown-menu-shortcut.svelte +20 -0
  44. package/src/shadcn/dropdown-menu copy/dropdown-menu-sub-content.svelte +16 -0
  45. package/src/shadcn/dropdown-menu copy/dropdown-menu-sub-trigger.svelte +29 -0
  46. package/src/shadcn/dropdown-menu copy/dropdown-menu-trigger.svelte +7 -0
  47. package/src/shadcn/spinner/index.ts +1 -0
  48. package/src/shadcn/spinner/spinner.svelte +9 -0
  49. package/src/shadcn/toggle/toggle.svelte +36 -45
  50. package/src/shadcn/toggle-group/toggle-group-item.svelte +20 -23
  51. package/src/shadcn/toggle-group/toggle-group.svelte +9 -1
  52. /package/dist/cli/template-files/src/lib/{Counter.svelte → counter.svelte} +0 -0
@@ -0,0 +1,72 @@
1
+ <script lang="ts" module>
2
+ import { getContext, setContext } from 'svelte';
3
+
4
+ type ToggleGroupContext = {
5
+ type: 'single' | 'multiple';
6
+ getValue: () => string | string[];
7
+ toggle: (itemValue: string) => void;
8
+ buttonWidth?: string;
9
+ };
10
+
11
+ export function setToggleGroupCtx(ctx: ToggleGroupContext) {
12
+ setContext('pika-toggle-group', ctx);
13
+ }
14
+
15
+ export function getToggleGroupCtx() {
16
+ return getContext<ToggleGroupContext>('pika-toggle-group');
17
+ }
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ import { cn } from '../../shadcn/utils.js';
22
+ import type { Snippet } from 'svelte';
23
+
24
+ type Props = {
25
+ value?: string | string[];
26
+ type?: 'single' | 'multiple';
27
+ buttonWidth?: string;
28
+ class?: string;
29
+ variant?: 'default' | 'outline';
30
+ children?: Snippet;
31
+ };
32
+
33
+ let {
34
+ type = 'single',
35
+ value = $bindable(type === 'single' ? '' : []),
36
+ buttonWidth,
37
+ class: className,
38
+ variant = 'outline',
39
+ children
40
+ }: Props = $props();
41
+
42
+ function toggle(itemValue: string) {
43
+ if (type === 'single') {
44
+ value = value === itemValue ? '' : itemValue;
45
+ } else {
46
+ const arr = Array.isArray(value) ? value : [];
47
+ const index = arr.indexOf(itemValue);
48
+ if (index > -1) {
49
+ value = arr.filter(v => v !== itemValue);
50
+ } else {
51
+ value = [...arr, itemValue];
52
+ }
53
+ }
54
+ }
55
+
56
+ setToggleGroupCtx({
57
+ type,
58
+ getValue: () => value,
59
+ toggle,
60
+ buttonWidth
61
+ });
62
+ </script>
63
+
64
+ <div
65
+ class={cn(
66
+ 'flex w-fit items-center',
67
+ className
68
+ )}
69
+ role="group"
70
+ >
71
+ {@render children?.()}
72
+ </div>
@@ -1,15 +1,17 @@
1
1
  <script lang="ts">
2
2
  import HelpCircleOutline from '$icons/ci/help-circle-outline';
3
+ import InfoIcon from '$icons/lucide/info';
4
+ import type { Snippet } from 'svelte';
3
5
  import * as Popover from '../../shadcn/popover';
4
6
  import { cn } from '../../shadcn/utils';
5
- import type { Snippet } from 'svelte';
6
7
 
7
8
  interface Props {
8
9
  popoverClasses?: string;
9
10
  children?: Snippet;
11
+ useInfoIcon?: boolean;
10
12
  }
11
13
 
12
- let { popoverClasses, children }: Props = $props();
14
+ let { popoverClasses, children, useInfoIcon = false }: Props = $props();
13
15
 
14
16
  let open = $state(false);
15
17
  </script>
@@ -24,7 +26,11 @@
24
26
  open = false;
25
27
  }}
26
28
  >
27
- <HelpCircleOutline class="w-4 h-4 text-gray-400 hover:text-blue-500 transition-colors" />
29
+ {#if useInfoIcon}
30
+ <InfoIcon class="w-4 h-4 text-gray-400 hover:text-blue-500 transition-colors" />
31
+ {:else}
32
+ <HelpCircleOutline class="w-4 h-4 text-gray-400 hover:text-blue-500 transition-colors" />
33
+ {/if}
28
34
  </Popover.Trigger>
29
35
 
30
36
  <Popover.Content class={cn('w-120', popoverClasses)}>
@@ -0,0 +1,69 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from '../utils.js';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import ChartStyle from './chart-style.svelte';
5
+ import { setChartContext, type ChartConfig } from './chart-utils.js';
6
+ const uid = $props.id();
7
+ let {
8
+ ref = $bindable(null),
9
+ id = uid,
10
+ class: className,
11
+ children,
12
+ config,
13
+ ...restProps
14
+ }: WithElementRef<HTMLAttributes<HTMLElement>> & {
15
+ config: ChartConfig;
16
+ } = $props();
17
+ const chartId = `chart-${id || uid.replace(/:/g, '')}`;
18
+ setChartContext({
19
+ get config() {
20
+ return config;
21
+ }
22
+ });
23
+ </script>
24
+
25
+ <div
26
+ bind:this={ref}
27
+ data-chart={chartId}
28
+ data-slot="chart"
29
+ class={cn(
30
+ 'flex aspect-video justify-center overflow-visible text-xs',
31
+ // Overrides
32
+ //
33
+ // Stroke around dots/marks when hovering
34
+ '[&_.stroke-white]:stroke-transparent',
35
+ // override the default stroke color of lines
36
+ '[&_.lc-line]:stroke-border/50',
37
+ // by default, layerchart shows a line intersecting the point when hovering, this hides that
38
+ '[&_.lc-highlight-line]:stroke-0',
39
+ // by default, when you hover a point on a stacked series chart, it will drop the opacity
40
+ // of the other series, this overrides that
41
+ '[&_.lc-area-path]:opacity-100 [&_.lc-highlight-line]:opacity-100 [&_.lc-highlight-point]:opacity-100 [&_.lc-spline-path]:opacity-100 [&_.lc-text-svg]:overflow-visible [&_.lc-text]:text-xs',
42
+ // We don't want the little tick lines between the axis labels and the chart, so we remove
43
+ // the stroke. The alternative is to manually disable `tickMarks` on the x/y axis of every
44
+ // chart.
45
+ '[&_.lc-axis-tick]:stroke-0',
46
+ // We don't want to display the rule on the x/y axis, as there is already going to be
47
+ // a grid line there and rule ends up overlapping the marks because it is rendered after
48
+ // the marks
49
+ '[&_.lc-rule-x-line:not(.lc-grid-x-rule)]:stroke-0 [&_.lc-rule-y-line:not(.lc-grid-y-rule)]:stroke-0',
50
+ '[&_.lc-grid-x-radial-line]:stroke-border [&_.lc-grid-x-radial-circle]:stroke-border',
51
+ '[&_.lc-grid-y-radial-line]:stroke-border [&_.lc-grid-y-radial-circle]:stroke-border',
52
+ // Legend adjustments
53
+ '[&_.lc-legend-swatch-button]:items-center [&_.lc-legend-swatch-button]:gap-1.5',
54
+ '[&_.lc-legend-swatch-group]:items-center [&_.lc-legend-swatch-group]:gap-4',
55
+ '[&_.lc-legend-swatch]:size-2.5 [&_.lc-legend-swatch]:rounded-[2px]',
56
+ // Labels
57
+ '[&_.lc-labels-text:not([fill])]:fill-foreground [&_text]:stroke-transparent',
58
+ // Tick labels on th x/y axes
59
+ '[&_.lc-axis-tick-label]:fill-muted-foreground [&_.lc-axis-tick-label]:font-normal',
60
+ '[&_.lc-tooltip-rects-g]:fill-transparent',
61
+ '[&_.lc-layout-svg-g]:fill-transparent',
62
+ '[&_.lc-root-container]:w-full',
63
+ className
64
+ )}
65
+ {...restProps}
66
+ >
67
+ <ChartStyle id={chartId} {config} />
68
+ {@render children?.()}
69
+ </div>
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ import { THEMES, type ChartConfig } from './chart-utils.js';
3
+ let { id, config }: { id: string; config: ChartConfig } = $props();
4
+ const colorConfig = $derived(config ? Object.entries(config).filter(([, config]) => config.theme || config.color) : null);
5
+ const themeContents = $derived.by(() => {
6
+ if (!colorConfig || !colorConfig.length) return;
7
+ const themeContents = [];
8
+ for (let [_theme, prefix] of Object.entries(THEMES)) {
9
+ let content = `${prefix} [data-chart=${id}] {\n`;
10
+ const color = colorConfig.map(([key, itemConfig]) => {
11
+ const theme = _theme as keyof typeof itemConfig.theme;
12
+ const color = itemConfig.theme?.[theme] || itemConfig.color;
13
+ return color ? `\t--color-${key}: ${color};` : null;
14
+ });
15
+ content += color.join('\n') + '\n}';
16
+ themeContents.push(content);
17
+ }
18
+ return themeContents.join('\n');
19
+ });
20
+ </script>
21
+
22
+ {#if themeContents}
23
+ {#key id}
24
+ <svelte:element this={'style'}>
25
+ {themeContents}
26
+ </svelte:element>
27
+ {/key}
28
+ {/if}
@@ -0,0 +1,126 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef, type WithoutChildren } from '../utils.js';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { getPayloadConfigFromPayload, useChart, type TooltipPayload } from './chart-utils.js';
5
+ import { getTooltipContext, Tooltip as TooltipPrimitive } from 'layerchart';
6
+ import type { Snippet } from 'svelte';
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ function defaultFormatter(value: any, _payload: TooltipPayload[]) {
9
+ return `${value}`;
10
+ }
11
+ let {
12
+ ref = $bindable(null),
13
+ class: className,
14
+ hideLabel = false,
15
+ indicator = 'dot',
16
+ hideIndicator = false,
17
+ labelKey,
18
+ label,
19
+ labelFormatter = defaultFormatter,
20
+ labelClassName,
21
+ formatter,
22
+ nameKey,
23
+ color,
24
+ ...restProps
25
+ }: WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & {
26
+ hideLabel?: boolean;
27
+ label?: string;
28
+ indicator?: 'line' | 'dot' | 'dashed';
29
+ nameKey?: string;
30
+ labelKey?: string;
31
+ hideIndicator?: boolean;
32
+ labelClassName?: string;
33
+ labelFormatter?: // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ ((value: any, payload: TooltipPayload[]) => string | number | Snippet) | null;
35
+ formatter?: Snippet<
36
+ [
37
+ {
38
+ value: unknown;
39
+ name: string;
40
+ item: TooltipPayload;
41
+ index: number;
42
+ payload: TooltipPayload[];
43
+ }
44
+ ]
45
+ >;
46
+ } = $props();
47
+ const chart = useChart();
48
+ const tooltipCtx = getTooltipContext();
49
+ const formattedLabel = $derived.by(() => {
50
+ if (hideLabel || !tooltipCtx.payload?.length) return null;
51
+ const [item] = tooltipCtx.payload;
52
+ const key = labelKey ?? item?.label ?? item?.name ?? 'value';
53
+ const itemConfig = getPayloadConfigFromPayload(chart.config, item, key);
54
+ const value = !labelKey && typeof label === 'string' ? (chart.config[label as keyof typeof chart.config]?.label ?? label) : (itemConfig?.label ?? item.label);
55
+ if (value === undefined) return null;
56
+ if (!labelFormatter) return value;
57
+ return labelFormatter(value, tooltipCtx.payload);
58
+ });
59
+ const nestLabel = $derived(tooltipCtx.payload.length === 1 && indicator !== 'dot');
60
+ </script>
61
+
62
+ {#snippet TooltipLabel()}
63
+ {#if formattedLabel}
64
+ <div class={cn('font-medium', labelClassName)}>
65
+ {#if typeof formattedLabel === 'function'}
66
+ {@render formattedLabel()}
67
+ {:else}
68
+ {formattedLabel}
69
+ {/if}
70
+ </div>
71
+ {/if}
72
+ {/snippet}
73
+ <TooltipPrimitive.Root variant="none">
74
+ <div class={cn('border-border/50 bg-background grid min-w-[9rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl', className)} {...restProps}>
75
+ {#if !nestLabel}
76
+ {@render TooltipLabel()}
77
+ {/if}
78
+ <div class="grid gap-1.5">
79
+ {#each tooltipCtx.payload as item, i (item.key + i)}
80
+ {@const key = `${nameKey || item.key || item.name || 'value'}`}
81
+ {@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)}
82
+ {@const indicatorColor = color || item.payload?.color || item.color}
83
+ <div class={cn('[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5', indicator === 'dot' && 'items-center')}>
84
+ {#if formatter && item.value !== undefined && item.name}
85
+ {@render formatter({
86
+ value: item.value,
87
+ name: item.name,
88
+ item,
89
+ index: i,
90
+ payload: tooltipCtx.payload
91
+ })}
92
+ {:else}
93
+ {#if itemConfig?.icon}
94
+ <itemConfig.icon />
95
+ {:else if !hideIndicator}
96
+ <div
97
+ style="--color-bg: {indicatorColor}; --color-border: {indicatorColor};"
98
+ class={cn('border-(--color-border) bg-(--color-bg) shrink-0 rounded-[2px]', {
99
+ 'size-2.5': indicator === 'dot',
100
+ 'h-full w-1': indicator === 'line',
101
+ 'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',
102
+ 'my-0.5': nestLabel && indicator === 'dashed'
103
+ })}
104
+ ></div>
105
+ {/if}
106
+ <div class={cn('flex flex-1 shrink-0 justify-between leading-none', nestLabel ? 'items-end' : 'items-center')}>
107
+ <div class="grid gap-1.5">
108
+ {#if nestLabel}
109
+ {@render TooltipLabel()}
110
+ {/if}
111
+ <span class="text-muted-foreground">
112
+ {itemConfig?.label || item.name}
113
+ </span>
114
+ </div>
115
+ {#if item.value !== undefined}
116
+ <span class="text-foreground font-mono font-medium tabular-nums">
117
+ {item.value.toLocaleString()}
118
+ </span>
119
+ {/if}
120
+ </div>
121
+ {/if}
122
+ </div>
123
+ {/each}
124
+ </div>
125
+ </div>
126
+ </TooltipPrimitive.Root>
@@ -0,0 +1,37 @@
1
+ import type { Tooltip } from 'layerchart';
2
+ import { getContext, setContext, type Component, type ComponentProps, type Snippet } from 'svelte';
3
+ export const THEMES = { light: '', dark: '.dark' } as const;
4
+ export type ChartConfig = {
5
+ [k in string]: {
6
+ label?: string;
7
+ icon?: Component;
8
+ } & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> });
9
+ };
10
+ export type ExtractSnippetParams<T> = T extends Snippet<[infer P]> ? P : never;
11
+ export type TooltipPayload = ExtractSnippetParams<ComponentProps<typeof Tooltip.Root>['children']>['payload'][number];
12
+ // Helper to extract item config from a payload.
13
+ export function getPayloadConfigFromPayload(config: ChartConfig, payload: TooltipPayload, key: string) {
14
+ if (typeof payload !== 'object' || payload === null) return undefined;
15
+ const payloadPayload = 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null ? payload.payload : undefined;
16
+ let configLabelKey: string = key;
17
+ if (payload.key === key) {
18
+ configLabelKey = payload.key;
19
+ } else if (payload.name === key) {
20
+ configLabelKey = payload.name;
21
+ } else if (key in payload && typeof payload[key as keyof typeof payload] === 'string') {
22
+ configLabelKey = payload[key as keyof typeof payload] as string;
23
+ } else if (payloadPayload !== undefined && key in payloadPayload && typeof payloadPayload[key as keyof typeof payloadPayload] === 'string') {
24
+ configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
25
+ }
26
+ return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
27
+ }
28
+ type ChartContextValue = {
29
+ config: ChartConfig;
30
+ };
31
+ const chartContextKey = Symbol('chart-context');
32
+ export function setChartContext(value: ChartContextValue) {
33
+ return setContext(chartContextKey, value);
34
+ }
35
+ export function useChart() {
36
+ return getContext<ChartContextValue>(chartContextKey);
37
+ }
@@ -0,0 +1,4 @@
1
+ import ChartContainer from './chart-container.svelte';
2
+ import ChartTooltip from './chart-tooltip.svelte';
3
+ export { getPayloadConfigFromPayload, type ChartConfig } from './chart-utils.js';
4
+ export { ChartContainer, ChartTooltip, ChartContainer as Container, ChartTooltip as Tooltip };
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
- import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
3
-
4
- let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
2
+ import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
+ let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
5
4
  </script>
6
5
 
7
6
  <DropdownMenuPrimitive.Group bind:ref data-slot="dropdown-menu-group" {...restProps} />
@@ -20,7 +20,7 @@
20
20
  data-inset={inset}
21
21
  data-variant={variant}
22
22
  class={cn(
23
- "data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
23
+ "data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-[highlighted]:bg-destructive/10 dark:data-[variant=destructive]:data-[highlighted]:bg-destructive/20 data-[variant=destructive]:data-[highlighted]:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
24
24
  className
25
25
  )}
26
26
  {...restProps}
@@ -13,12 +13,6 @@
13
13
  } = $props();
14
14
  </script>
15
15
 
16
- <div
17
- bind:this={ref}
18
- data-slot="dropdown-menu-label"
19
- data-inset={inset}
20
- class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)}
21
- {...restProps}
22
- >
16
+ <div bind:this={ref} data-slot="dropdown-menu-label" data-inset={inset} class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)} {...restProps}>
23
17
  {@render children?.()}
24
18
  </div>
@@ -1,16 +1,6 @@
1
1
  <script lang="ts">
2
- import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
3
-
4
- let {
5
- ref = $bindable(null),
6
- value = $bindable(),
7
- ...restProps
8
- }: DropdownMenuPrimitive.RadioGroupProps = $props();
2
+ import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
+ let { ref = $bindable(null), value = $bindable(), ...restProps }: DropdownMenuPrimitive.RadioGroupProps = $props();
9
4
  </script>
10
5
 
11
- <DropdownMenuPrimitive.RadioGroup
12
- bind:ref
13
- bind:value
14
- data-slot="dropdown-menu-radio-group"
15
- {...restProps}
16
- />
6
+ <DropdownMenuPrimitive.RadioGroup bind:ref bind:value data-slot="dropdown-menu-radio-group" {...restProps} />
@@ -2,7 +2,6 @@
2
2
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
3
  import CircleIcon from '$icons/lucide/circle';
4
4
  import { cn, type WithoutChild } from '../utils.js';
5
-
6
5
  let { ref = $bindable(null), class: className, children: childrenProp, ...restProps }: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props();
7
6
  </script>
8
7
 
@@ -1,13 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
3
  import { cn } from '../utils.js';
4
-
5
4
  let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SeparatorProps = $props();
6
5
  </script>
7
6
 
8
- <DropdownMenuPrimitive.Separator
9
- bind:ref
10
- data-slot="dropdown-menu-separator"
11
- class={cn('bg-border -mx-1 my-1 h-px', className)}
12
- {...restProps}
13
- />
7
+ <DropdownMenuPrimitive.Separator bind:ref data-slot="dropdown-menu-separator" class={cn('bg-border -mx-1 my-1 h-px', className)} {...restProps} />
@@ -1,20 +1,9 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import { cn, type WithElementRef } from '../utils.js';
4
-
5
- let {
6
- ref = $bindable(null),
7
- class: className,
8
- children,
9
- ...restProps
10
- }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
4
+ let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
11
5
  </script>
12
6
 
13
- <span
14
- bind:this={ref}
15
- data-slot="dropdown-menu-shortcut"
16
- class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
17
- {...restProps}
18
- >
7
+ <span bind:this={ref} data-slot="dropdown-menu-shortcut" class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)} {...restProps}>
19
8
  {@render children?.()}
20
9
  </span>
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
3
  import { cn } from '../utils.js';
4
-
5
4
  let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SubContentProps = $props();
6
5
  </script>
7
6
 
@@ -2,7 +2,6 @@
2
2
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
3
  import ChevronRightIcon from '$icons/lucide/chevron-right';
4
4
  import { cn } from '../utils.js';
5
-
6
5
  let {
7
6
  ref = $bindable(null),
8
7
  class: className,
@@ -19,7 +18,7 @@
19
18
  data-slot="dropdown-menu-sub-trigger"
20
19
  data-inset={inset}
21
20
  class={cn(
22
- "data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground outline-hidden [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
21
+ "data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground outline-hidden [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
23
22
  className
24
23
  )}
25
24
  {...restProps}
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
- import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
3
-
4
- let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
2
+ import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
+ let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
5
4
  </script>
6
5
 
7
6
  <DropdownMenuPrimitive.Trigger bind:ref data-slot="dropdown-menu-trigger" {...restProps} />
@@ -1,49 +1,48 @@
1
- import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
2
- import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
3
- import Content from "./dropdown-menu-content.svelte";
4
- import Group from "./dropdown-menu-group.svelte";
5
- import Item from "./dropdown-menu-item.svelte";
6
- import Label from "./dropdown-menu-label.svelte";
7
- import RadioGroup from "./dropdown-menu-radio-group.svelte";
8
- import RadioItem from "./dropdown-menu-radio-item.svelte";
9
- import Separator from "./dropdown-menu-separator.svelte";
10
- import Shortcut from "./dropdown-menu-shortcut.svelte";
11
- import Trigger from "./dropdown-menu-trigger.svelte";
12
- import SubContent from "./dropdown-menu-sub-content.svelte";
13
- import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
14
- import GroupHeading from "./dropdown-menu-group-heading.svelte";
1
+ import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
2
+ import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
3
+ import Content from './dropdown-menu-content.svelte';
4
+ import Group from './dropdown-menu-group.svelte';
5
+ import Item from './dropdown-menu-item.svelte';
6
+ import Label from './dropdown-menu-label.svelte';
7
+ import RadioGroup from './dropdown-menu-radio-group.svelte';
8
+ import RadioItem from './dropdown-menu-radio-item.svelte';
9
+ import Separator from './dropdown-menu-separator.svelte';
10
+ import Shortcut from './dropdown-menu-shortcut.svelte';
11
+ import Trigger from './dropdown-menu-trigger.svelte';
12
+ import SubContent from './dropdown-menu-sub-content.svelte';
13
+ import SubTrigger from './dropdown-menu-sub-trigger.svelte';
14
+ import GroupHeading from './dropdown-menu-group-heading.svelte';
15
15
  const Sub = DropdownMenuPrimitive.Sub;
16
16
  const Root = DropdownMenuPrimitive.Root;
17
-
18
17
  export {
19
- CheckboxItem,
20
- Content,
21
- Root as DropdownMenu,
22
- CheckboxItem as DropdownMenuCheckboxItem,
23
- Content as DropdownMenuContent,
24
- Group as DropdownMenuGroup,
25
- Item as DropdownMenuItem,
26
- Label as DropdownMenuLabel,
27
- RadioGroup as DropdownMenuRadioGroup,
28
- RadioItem as DropdownMenuRadioItem,
29
- Separator as DropdownMenuSeparator,
30
- Shortcut as DropdownMenuShortcut,
31
- Sub as DropdownMenuSub,
32
- SubContent as DropdownMenuSubContent,
33
- SubTrigger as DropdownMenuSubTrigger,
34
- Trigger as DropdownMenuTrigger,
35
- GroupHeading as DropdownMenuGroupHeading,
36
- Group,
37
- GroupHeading,
38
- Item,
39
- Label,
40
- RadioGroup,
41
- RadioItem,
42
- Root,
43
- Separator,
44
- Shortcut,
45
- Sub,
46
- SubContent,
47
- SubTrigger,
48
- Trigger,
18
+ CheckboxItem,
19
+ Content,
20
+ Root as DropdownMenu,
21
+ CheckboxItem as DropdownMenuCheckboxItem,
22
+ Content as DropdownMenuContent,
23
+ Group as DropdownMenuGroup,
24
+ Item as DropdownMenuItem,
25
+ Label as DropdownMenuLabel,
26
+ RadioGroup as DropdownMenuRadioGroup,
27
+ RadioItem as DropdownMenuRadioItem,
28
+ Separator as DropdownMenuSeparator,
29
+ Shortcut as DropdownMenuShortcut,
30
+ Sub as DropdownMenuSub,
31
+ SubContent as DropdownMenuSubContent,
32
+ SubTrigger as DropdownMenuSubTrigger,
33
+ Trigger as DropdownMenuTrigger,
34
+ GroupHeading as DropdownMenuGroupHeading,
35
+ Group,
36
+ GroupHeading,
37
+ Item,
38
+ Label,
39
+ RadioGroup,
40
+ RadioItem,
41
+ Root,
42
+ Separator,
43
+ Shortcut,
44
+ Sub,
45
+ SubContent,
46
+ SubTrigger,
47
+ Trigger
49
48
  };
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
3
+ import CheckIcon from '$icons/lucide/check';
4
+ import MinusIcon from '$icons/lucide/minus';
5
+ import { cn, type WithoutChildrenOrChild } from '../utils.js';
6
+ import type { Snippet } from 'svelte';
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ checked = $bindable(false),
11
+ indeterminate = $bindable(false),
12
+ class: className,
13
+ children: childrenProp,
14
+ ...restProps
15
+ }: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & {
16
+ children?: Snippet;
17
+ } = $props();
18
+ </script>
19
+
20
+ <DropdownMenuPrimitive.CheckboxItem
21
+ bind:ref
22
+ bind:checked
23
+ bind:indeterminate
24
+ data-slot="dropdown-menu-checkbox-item"
25
+ class={cn(
26
+ "focus:bg-accent focus:text-accent-foreground outline-hidden relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
27
+ className
28
+ )}
29
+ {...restProps}
30
+ >
31
+ {#snippet children({ checked, indeterminate })}
32
+ <span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
33
+ {#if indeterminate}
34
+ <MinusIcon class="size-4" />
35
+ {:else}
36
+ <CheckIcon class={cn('size-4', !checked && 'text-transparent')} />
37
+ {/if}
38
+ </span>
39
+ {@render childrenProp?.()}
40
+ {/snippet}
41
+ </DropdownMenuPrimitive.CheckboxItem>