wip improvements but still problematic
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" module>
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
||||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Checkbox as CheckboxPrimitive } from 'bits-ui';
|
||||
import CheckIcon from '@lucide/svelte/icons/check';
|
||||
import MinusIcon from '@lucide/svelte/icons/minus';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import XIcon from '@lucide/svelte/icons/x';
|
||||
import type { Snippet } from 'svelte';
|
||||
import * as Dialog from './index.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
|
||||
type InputType = Exclude<HTMLInputTypeAttribute, 'file'>;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Label as LabelPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import SelectPortal from './select-portal.svelte';
|
||||
import SelectScrollUpButton from './select-scroll-up-button.svelte';
|
||||
import SelectScrollDownButton from './select-scroll-down-button.svelte';
|
||||
import { cn, type WithoutChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChild } from '$lib/utils/ui.js';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
import type { WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import type { WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import CheckIcon from '@lucide/svelte/icons/check';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import { cn, type WithoutChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||
import { cn, type WithElementRef } from '$lib/utils/ui.js';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||
import { Separator } from '$lib/components/ui/separator/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
|
||||
import { cn, type WithoutChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { cn } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Switch as SwitchPrimitive } from 'bits-ui';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
|
||||
import { cn, type WithoutChildrenOrChild } from '$lib/utils/ui.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
||||
@@ -1,24 +1,127 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { type Writable, writable } from 'svelte/store';
|
||||
|
||||
// Placeholder function for urlHashStore
|
||||
// In a real application, this would handle URL hash parameters
|
||||
// and return a Svelte store that reflects those parameters.
|
||||
export function urlHashStore(initialValue: Record<string, unknown>) {
|
||||
const { subscribe, set, update } = writable(initialValue);
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
|
||||
// In a full implementation, you would add logic here to:
|
||||
// 1. Read the URL hash on initialization
|
||||
// 2. Parse the hash into an object
|
||||
// 3. Update the store with these values
|
||||
// 4. Listen for changes to the store and update the URL hash accordingly
|
||||
// 5. Listen for URL hash changes (e.g., back/forward buttons) and update the store
|
||||
import { debounce, isNumeric } from '$lib/utils';
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set,
|
||||
update,
|
||||
// You might want to add methods to easily update specific hash parameters
|
||||
updateParam: (key: string, value: unknown) =>
|
||||
update((current) => ({ ...current, [key]: value }))
|
||||
import type { Parameters } from '$lib/docs';
|
||||
|
||||
export type UrlHashStore = Writable<Parameters>;
|
||||
|
||||
export const urlHashStore = (initialValues: Parameters): UrlHashStore => {
|
||||
const urlHashes: Writable<Parameters> = writable({});
|
||||
|
||||
const defaultValues = JSON.parse(JSON.stringify(initialValues));
|
||||
urlHashes.set(JSON.parse(JSON.stringify(defaultValues)));
|
||||
|
||||
function updateURL() {
|
||||
const searchParams = page.url.searchParams.toString().replaceAll('%2C', ',');
|
||||
const link = `?${searchParams}${page.url.hash ?? ''}`;
|
||||
if (page.url.search !== window.location.search) {
|
||||
goto(link, {
|
||||
noScroll: true,
|
||||
keepFocus: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const processURLParamsUpdate = debounce(() => updateURL());
|
||||
|
||||
const updateURLParams = (values: Parameters) => {
|
||||
if (browser) {
|
||||
let changedParams = false;
|
||||
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
let defaultValue = defaultValues[key];
|
||||
|
||||
// params key is array
|
||||
if (defaultValue && Array === defaultValue.constructor) {
|
||||
if (JSON.stringify(value) === JSON.stringify(defaultValue)) {
|
||||
if (page.url.searchParams.has(key) && page.url.searchParams.get(key) !== value) {
|
||||
page.url.searchParams.delete(key);
|
||||
changedParams = true;
|
||||
}
|
||||
} else {
|
||||
let array = value;
|
||||
// remove empty string when array has more then 1 values
|
||||
if (array.length > 1 && array.includes('')) {
|
||||
array = value.filter((e: string) => e !== '');
|
||||
}
|
||||
page.url.searchParams.set(key, array.join(','));
|
||||
changedParams = true;
|
||||
}
|
||||
} else {
|
||||
let val: number | string = value;
|
||||
if (isNumeric(defaultValue)) {
|
||||
defaultValue = Number(defaultValue);
|
||||
}
|
||||
if (isNumeric(value)) {
|
||||
val = Number(value);
|
||||
}
|
||||
|
||||
if (val != defaultValue) {
|
||||
page.url.searchParams.set(key, String(val));
|
||||
changedParams = true;
|
||||
} else {
|
||||
if (page.url.searchParams.has(key) && page.url.searchParams.get(key) !== val) {
|
||||
page.url.searchParams.delete(key);
|
||||
changedParams = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (page.url.searchParams.has(key) && page.url.searchParams.get(key) === '') {
|
||||
if (
|
||||
defaultValue === undefined ||
|
||||
(defaultValue && Array === defaultValue.constructor && defaultValue.length === 0) ||
|
||||
defaultValue === '0'
|
||||
) {
|
||||
page.url.searchParams.delete(key);
|
||||
changedParams = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changedParams) {
|
||||
processURLParamsUpdate();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// check if urlParams overrides any default values OR stored values
|
||||
if (browser && page.url.search) {
|
||||
for (const [key, value] of page.url.searchParams.entries()) {
|
||||
let defaultValue = defaultValues[key];
|
||||
|
||||
if (defaultValue && defaultValue.constructor === Array) {
|
||||
if (JSON.stringify(defaultValue) !== JSON.stringify(value)) {
|
||||
urlHashes.update((urlValues) => {
|
||||
urlValues[key] = value.split(/,|%2C/);
|
||||
return urlValues;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let val: number | string = value;
|
||||
if (isNumeric(defaultValue)) {
|
||||
defaultValue = Number(defaultValue);
|
||||
}
|
||||
if (isNumeric(value)) {
|
||||
val = Number(value);
|
||||
}
|
||||
if (defaultValue !== val) {
|
||||
urlHashes.update((urlValues) => {
|
||||
urlValues[key] = val;
|
||||
return urlValues;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlHashes.subscribe((values) => {
|
||||
updateURLParams(values);
|
||||
});
|
||||
|
||||
return urlHashes;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
export const isNumeric = (num: string | number) =>
|
||||
(typeof num === 'number' || (typeof num === 'string' && num.trim() !== '')) &&
|
||||
!isNaN(num as number);
|
||||
|
||||
export const pad = (n: string | number) => {
|
||||
if (n === null || n === undefined) {
|
||||
return '';
|
||||
}
|
||||
return ('0' + n).slice(-2);
|
||||
};
|
||||
|
||||
export function debounce<F extends (...args: unknown[]) => unknown>(
|
||||
func: F,
|
||||
timeout = 100
|
||||
): (this: ThisParameterType<F>, ...args: Parameters<F>) => void {
|
||||
let timer: ReturnType<typeof setTimeout>;
|
||||
return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
func.apply(this, args);
|
||||
}, timeout);
|
||||
};
|
||||
}
|
||||
@@ -11,10 +11,3 @@ export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T;
|
||||
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T;
|
||||
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
|
||||
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
|
||||
|
||||
export const pad = (n: string | number) => {
|
||||
if (n === null || n === undefined) {
|
||||
return '';
|
||||
}
|
||||
return ('0' + n).slice(-2);
|
||||
};
|
||||
Reference in New Issue
Block a user