Forráskód Böngészése

[stdf]Update ActionSheet compoent, demo and documents.

dufu1991 1 éve
szülő
commit
c1565c9b94

+ 48 - 53
demo/src/routes/en_US/actionSheet/+page.svelte

@@ -17,6 +17,34 @@
 
 	const actions = [{ content: 'Option one' }, { content: 'Option two' }, { content: 'Option three' }];
 
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions1 = [
+		{ content: 'Normal option' },
+		{ content: 'Theme option', style: 'theme' },
+		{ content: 'Disabled option', style: 'disabled' },
+		{ content: 'Danger option', style: 'danger' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions2 = [
+		{ content: 'Option one' },
+		{ content: 'Option two', desc: 'Here is the description information' },
+		{ content: 'Option three', style: 'danger', desc: 'Here is the description information' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions3 = [
+		{ content: 'Lina', showImg: true, imgSrc: '/assets/images/dota_火女.png', imgRadius: 'base' },
+		{ content: 'SB', showImg: true, imgSrc: '/assets/images/dota_小牛.png', imgRadius: 'base' },
+		{ content: 'Morph', showImg: true, imgSrc: '/assets/images/dota_水人.png', imgRadius: 'base' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions4 = [
+		{ content: 'Apple', showImg: true, imgSrc: '/assets/logos/apple.png', imgRadius: 'none' },
+		{ content: 'Google', showImg: true, imgSrc: '/assets/logos/google.png', imgRadius: 'none' },
+		{ content: 'Microsoft', showImg: true, imgSrc: '/assets/logos/microsoft.png', imgRadius: 'none' },
+		{ content: 'Adobe', showImg: true, imgSrc: '/assets/logos/adobe.png', imgRadius: 'none' },
+		{ content: 'Figma', showImg: true, imgSrc: '/assets/logos/figma.png', imgRadius: 'none' },
+	];
+
 	let toastVisible1 = $state(false);
 	let toastVisible2 = $state(false);
 	let toastVisible3 = $state(false);
@@ -33,72 +61,39 @@
 	<Cell title="Basic usage" onclick={() => (visible1 = true)} />
 	<ActionSheet bind:visible={visible1} {actions} />
 
-	<Cell title="If you have canceled operation and click on the mask, you cannot turn off" onclick={() => (visible2 = true)} />
+	<Cell title="With cancel operation and click mask not closable" onclick={() => (visible2 = true)} />
 	<ActionSheet bind:visible={visible2} {actions} showCancel popup={{ maskClosable: false }} />
 
 	<Cell title="Different styles" onclick={() => (visible3 = true)} />
-	<ActionSheet
-		bind:visible={visible3}
-		actions={[
-			{ content: 'Conventional option' },
-			{ content: 'Theme option', style: 'theme' },
-			{ content: 'Disable option', style: 'disabled' },
-			{ content: 'Warning option', style: 'danger' },
-		]}
-	/>
-
-	<Cell title="Title and description information" onclick={() => (visible4 = true)} />
-	<ActionSheet
-		bind:visible={visible4}
-		actions={[
-			{ content: 'Option one' },
-			{ content: 'Option two', desc: 'Here is description information description information' },
-			{ content: 'Option three', desc: 'Here is description information' },
-		]}
-		title="This is the title, which can be briefly explained."
-	/>
-
-	<Cell title="Come on the top" onclick={() => (visible5 = true)} />
+	<ActionSheet bind:visible={visible3} actions={actions1} />
+
+	<Cell title="With title and description information" onclick={() => (visible4 = true)} />
+	<ActionSheet bind:visible={visible4} actions={actions2} title="Here is the title, which can briefly explain the following operations." />
+
+	<Cell title="Top corner rounded" onclick={() => (visible5 = true)} />
 	<ActionSheet bind:visible={visible5} {actions} popup={{ radius: 'xl' }} />
 
-	<Cell title="There is a spacing on both sides" onclick={() => (visible6 = true)} />
+	<Cell title="With spacing on both sides" onclick={() => (visible6 = true)} />
 	<ActionSheet bind:visible={visible6} {actions} popup={{ radius: 'xl', px: '2' }} />
 
-	<Cell title="Supervision and closing incident" onclick={() => (visible7 = true)} />
+	<Cell title="Listen to close event" onclick={() => (visible7 = true)} />
 	<ActionSheet bind:visible={visible7} {actions} onclose={() => (toastVisible1 = true)} />
-	<Toast bind:visible={toastVisible1} message="closed ActionSheet!" />
+	<Toast bind:visible={toastVisible1} message="Closed ActionSheet!" />
 
-	<Cell title="Supervision and canceling incident" onclick={() => (visible8 = true)} />
+	<Cell title="Listen to cancel event" onclick={() => (visible8 = true)} />
 	<ActionSheet bind:visible={visible8} {actions} showCancel oncancel={() => (toastVisible2 = true)} />
-	<Toast bind:visible={toastVisible2} message="Click to cancel!" />
+	<Toast bind:visible={toastVisible2} message="Clicked cancel!" />
 
-	<Cell title="Survening options click event" onclick={() => (visible9 = true)} />
+	<Cell title="Listen to option click event" onclick={() => (visible9 = true)} />
 	<ActionSheet bind:visible={visible9} {actions} onclickAction={clickActionFunc} />
-	<Toast bind:visible={toastVisible3} message={`Click the ${index + 1} item,${item.content}!`} />
+	<Toast bind:visible={toastVisible3} message={`Clicked the ${index + 1} item, ${item.content}!`} />
 
-	<Cell title="Click the option not to be closed" onclick={() => (visible10 = true)} />
+	<Cell title="Click option not close" onclick={() => (visible10 = true)} />
 	<ActionSheet bind:visible={visible10} {actions} actionClosable={false} />
 
-	<Cell title="Options with pictures" onclick={() => (visible11 = true)} />
-	<ActionSheet
-		bind:visible={visible11}
-		actions={[
-			{ content: 'Lina', showImg: true, imgSrc: '/assets/images/dota_火女.png', imgRadius: 'base' },
-			{ content: 'Earthshaker', showImg: true, imgSrc: '/assets/images/dota_小牛.png', imgRadius: 'base' },
-			{ content: 'Morphling', showImg: true, imgSrc: '/assets/images/dota_水人.png', imgRadius: 'base' },
-		]}
-	/>
-
-	<Cell title="Option left" onclick={() => (visible12 = true)} />
-	<ActionSheet
-		bind:visible={visible12}
-		actions={[
-			{ content: 'Apple', showImg: true, imgSrc: '/assets/logos/apple.png', imgRadius: 'none' },
-			{ content: 'Google', showImg: true, imgSrc: '/assets/logos/google.png', imgRadius: 'none' },
-			{ content: 'Microsoft', showImg: true, imgSrc: '/assets/logos/microsoft.png', imgRadius: 'none' },
-			{ content: 'Adobe', showImg: true, imgSrc: '/assets/logos/adobe.png', imgRadius: 'none' },
-			{ content: 'Figma', showImg: true, imgSrc: '/assets/logos/figma.png', imgRadius: 'none' },
-		]}
-		align="left"
-	/>
+	<Cell title="Option with image" onclick={() => (visible11 = true)} />
+	<ActionSheet bind:visible={visible11} actions={actions3} />
+
+	<Cell title="Option left aligned" onclick={() => (visible12 = true)} />
+	<ActionSheet bind:visible={visible12} actions={actions4} align="left" />
 </div>

+ 32 - 37
demo/src/routes/zh_CN/actionSheet/+page.svelte

@@ -17,6 +17,34 @@
 
 	const actions = [{ content: '选项一' }, { content: '选项二' }, { content: '选项三' }];
 
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions1 = [
+		{ content: '常规选项' },
+		{ content: '主题选项', style: 'theme' },
+		{ content: '禁用选项', style: 'disabled' },
+		{ content: '警告选项', style: 'danger' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions2 = [
+		{ content: '选项一' },
+		{ content: '选项二', desc: '这里是描述信息' },
+		{ content: '选项三', style: 'danger', desc: '这里是描述信息' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions3 = [
+		{ content: '火女', showImg: true, imgSrc: '/assets/images/dota_火女.png', imgRadius: 'base' },
+		{ content: '小牛', showImg: true, imgSrc: '/assets/images/dota_小牛.png', imgRadius: 'base' },
+		{ content: '水人', showImg: true, imgSrc: '/assets/images/dota_水人.png', imgRadius: 'base' },
+	];
+	/** @type {import('../../../../../packages/stdf/index.d').Action[]} */
+	const actions4 = [
+		{ content: 'Apple', showImg: true, imgSrc: '/assets/logos/apple.png', imgRadius: 'none' },
+		{ content: 'Google', showImg: true, imgSrc: '/assets/logos/google.png', imgRadius: 'none' },
+		{ content: 'Microsoft', showImg: true, imgSrc: '/assets/logos/microsoft.png', imgRadius: 'none' },
+		{ content: 'Adobe', showImg: true, imgSrc: '/assets/logos/adobe.png', imgRadius: 'none' },
+		{ content: 'Figma', showImg: true, imgSrc: '/assets/logos/figma.png', imgRadius: 'none' },
+	];
+
 	let toastVisible1 = $state(false);
 	let toastVisible2 = $state(false);
 	let toastVisible3 = $state(false);
@@ -37,26 +65,10 @@
 	<ActionSheet bind:visible={visible2} {actions} showCancel popup={{ maskClosable: false }} />
 
 	<Cell title="不同样式" onclick={() => (visible3 = true)} />
-	<ActionSheet
-		bind:visible={visible3}
-		actions={[
-			{ content: '常规选项' },
-			{ content: '主题选项', style: 'theme' },
-			{ content: '禁用选项', style: 'disabled' },
-			{ content: '警告选项', style: 'danger' },
-		]}
-	/>
+	<ActionSheet bind:visible={visible3} actions={actions1} />
 
 	<Cell title="带标题和描述信息" onclick={() => (visible4 = true)} />
-	<ActionSheet
-		bind:visible={visible4}
-		actions={[
-			{ content: '选项一' },
-			{ content: '选项二', desc: '这里是描述信息' },
-			{ content: '选项三', style: 'danger', desc: '这里是描述信息' },
-		]}
-		title="这里是标题,可以简要说明以下操作。"
-	/>
+	<ActionSheet bind:visible={visible4} actions={actions2} title="这里是标题,可以简要说明以下操作。" />
 
 	<Cell title="顶部来点圆角" onclick={() => (visible5 = true)} />
 	<ActionSheet bind:visible={visible5} {actions} popup={{ radius: 'xl' }} />
@@ -80,25 +92,8 @@
 	<ActionSheet bind:visible={visible10} {actions} actionClosable={false} />
 
 	<Cell title="选项带图片" onclick={() => (visible11 = true)} />
-	<ActionSheet
-		bind:visible={visible11}
-		actions={[
-			{ content: '火女', showImg: true, imgSrc: '/assets/images/dota_火女.png', imgRadius: 'base' },
-			{ content: '小牛', showImg: true, imgSrc: '/assets/images/dota_小牛.png', imgRadius: 'base' },
-			{ content: '水人', showImg: true, imgSrc: '/assets/images/dota_水人.png', imgRadius: 'base' },
-		]}
-	/>
+	<ActionSheet bind:visible={visible11} actions={actions3} />
 
 	<Cell title="选项左对齐" onclick={() => (visible12 = true)} />
-	<ActionSheet
-		bind:visible={visible12}
-		actions={[
-			{ content: 'Apple', showImg: true, imgSrc: '/assets/logos/apple.png', imgRadius: 'none' },
-			{ content: 'Google', showImg: true, imgSrc: '/assets/logos/google.png', imgRadius: 'none' },
-			{ content: 'Microsoft', showImg: true, imgSrc: '/assets/logos/microsoft.png', imgRadius: 'none' },
-			{ content: 'Adobe', showImg: true, imgSrc: '/assets/logos/adobe.png', imgRadius: 'none' },
-			{ content: 'Figma', showImg: true, imgSrc: '/assets/logos/figma.png', imgRadius: 'none' },
-		]}
-		align="left"
-	/>
+	<ActionSheet bind:visible={visible12} actions={actions4} align="left" />
 </div>

+ 43 - 57
packages/stdf/components/actionSheet/ActionSheet.svelte

@@ -25,67 +25,52 @@
 		onclose,
 	} = $props();
 
-	// 标题对齐方式
-	// Title alignment
-	const titleAlignClass = { left: 'text-left', center: 'text-center', right: 'text-right' };
-
-	// 选项样式
-	// Option style
-	const stateClass = {
-		normal: ' ',
-		theme: ' text-primary dark:text-dark ',
-		danger: ' text-error ',
-		disabled: ' text-black/20 dark:text-white/20 ',
+	// 静态样式类定义移到组件外部
+	// static style class definition moved to component outside
+	const STYLE_MAPS = {
+		titleAlign: { left: 'text-left', center: 'text-center', right: 'text-right' },
+		state: { normal: ' ', theme: ' text-primary dark:text-dark ', danger: ' text-error ', disabled: ' text-black/20 dark:text-white/20 ' },
+		imgRadius: { none: 'rounded-none', base: 'rounded', full: 'rounded-full', lg: 'rounded-lg' },
+		align: { left: 'justify-start pl-4', center: 'justify-center', right: 'justify-end pr-4' },
 	};
 
-	// 图片圆角
-	// Image radius
-	const imgRadiusClass = { none: 'rounded-none', base: 'rounded', full: 'rounded-full', lg: 'rounded-lg' };
-
-	// 对齐方式
-	// alignment
-	const alignClass = { left: 'justify-start pl-4', center: 'justify-center', right: 'justify-end pr-4' };
-
-	// 计算弹出层高度
-	// Calculate the height of the popup
-	const getTransitionDistanceunc = (title, showCancel, actions) => {
-		const titleHeight = title ? 40 : 0;
-		const cancelHeight = showCancel ? 56 : 0;
-		// 循环 actions,如果有 desc 高度为 61, 没有 desc 高度为 56,分割线每条1px,计算总高度
-		// Loop actions, if there is desc, the height is 61, if there is no desc, the height is 56, and the divider is 1px each, and the total height is calculated
-		const actionsHeight = actions.reduce((total, item) => {
-			return total + (item.desc ? 60 : 56);
-		}, 0);
-		return titleHeight + cancelHeight + actionsHeight + actions.length - 1;
+	// 优化高度计算函数
+	// optimize height calculation function
+	const getTransitionDistance = (title, showCancel, actions) => {
+		const BASE_HEIGHTS = { title: 40, cancel: 56, action: 56, actionWithDesc: 60, divider: 1 };
+		return (
+			(title ? BASE_HEIGHTS.title : 0) +
+			(showCancel ? BASE_HEIGHTS.cancel : 0) +
+			actions.reduce((total, item) => total + (item.desc ? BASE_HEIGHTS.actionWithDesc : BASE_HEIGHTS.action), 0) +
+			(actions.length - 1) * BASE_HEIGHTS.divider
+		);
 	};
 
-	// 取消按钮点击事件
-	// Click event of cancel button
-	const cancelFunc = () => {
+	// 优化事件处理函数
+	// optimize event handling function
+	const handleCancel = () => {
 		visible = false;
-		oncancel && oncancel();
-		onclose && onclose();
+		oncancel?.();
+		onclose?.();
 	};
 
-	// 选项点击事件,如果选项不可点击,不触发事件,如果可点击,触发事件,如果 actionClosable 为 true,关闭弹出层
-	// Click event of action, if the action is not clickable, the event will not be triggered, if it is clickable, the event will be triggered, and if actionClosable is true, the popup will be closed
-	const clickActionFunc = (index, item) => {
-		if (item.style !== 'disabled') {
-			onclickAction && onclickAction(index, item); // 如果 clickAction 存在,执行 clickAction 函数
-			if (actionClosable) {
-				visible = false;
-				onclose && onclose();
-			}
+	// 处理选项点击事件
+	// handle option click event
+	const handleActionClick = (index, item) => {
+		if (item.style === 'disabled') return;
+		onclickAction?.(index, item);
+		if (actionClosable) {
+			visible = false;
+			onclose?.();
 		}
 	};
 </script>
 
-<Popup bind:visible size={0} maskClosable transitionDistance={getTransitionDistanceunc(title, showCancel, actions)} {onclose} {...popup}>
+<Popup bind:visible size={0} transitionDistance={getTransitionDistance(title, showCancel, actions)} {onclose} {...popup}>
 	{#if title}
 		<div
-			class="truncate text-xs text-black/50 dark:text-white/50 border-b border-black/5 dark:border-white/5 h-10 flex flex-col justify-center {titleAlignClass[
-				titleAlign
-			] || titleAlignClass['left']}"
+			class="truncate text-xs text-black/50 dark:text-white/50 border-b border-black/5 dark:border-white/5 h-10 flex flex-col justify-center {STYLE_MAPS
+				.titleAlign[titleAlign] || STYLE_MAPS.titleAlign['left']}"
 		>
 			{title}
 		</div>
@@ -93,20 +78,21 @@
 	<div>
 		{#each actions as item, index}
 			<button
-				class="{item.style !== 'disabled' ? 'active:scale-90 ' : ''}transition-all flex items-center gap-2 w-full {alignClass[align] ||
-					alignClass['center']}"
-				onclick={() => clickActionFunc(index, item)}
+				class="{item.style !== 'disabled'
+					? 'active:scale-90 '
+					: 'cursor-not-allowed '}transition-all flex items-center gap-2 w-full {STYLE_MAPS.align[align] || STYLE_MAPS.align['center']}"
+				disabled={item.style === 'disabled'}
+				onclick={() => handleActionClick(index, item)}
 			>
 				{#if item.showImg}
-					<div class="w-6 h-6 overflow-hidden {imgRadiusClass[item.imgRadius] || 'rounded-full'}">
+					<div class="w-6 h-6 overflow-hidden {STYLE_MAPS.imgRadius[item.imgRadius] || 'rounded-full'}">
 						<img class="w-full h-full object-cover" src={item.imgSrc} alt="" />
 					</div>
 				{/if}
 				<div>
 					<div
-						class="truncate text-center font-bold {stateClass[item.style] || stateClass.normal} flex flex-col justify-center {item.desc
-							? ' h-10'
-							: ' h-14'}"
+						class="truncate text-center font-bold {STYLE_MAPS.state[item.style] ||
+							STYLE_MAPS.state.normal} flex flex-col justify-center {item.desc ? ' h-10' : ' h-14'}"
 					>
 						{item.content}
 					</div>
@@ -123,8 +109,8 @@
 	{#if showCancel}
 		<div class="bg-black/5 dark:bg-white/5 h-2"></div>
 		<button
-			class="active:scale-90 transition-all h-12 flex items-center w-full {alignClass[align] || alignClass['center']}"
-			onclick={cancelFunc}
+			class="active:scale-90 transition-all h-12 flex items-center w-full {STYLE_MAPS.align[align] || STYLE_MAPS.align['center']}"
+			onclick={handleCancel}
 		>
 			<div>
 				{cancelText}