Skip to content

Commit

Permalink
feat(selection): add disabled props
Browse files Browse the repository at this point in the history
  • Loading branch information
chizukicn committed Sep 17, 2023
1 parent 60f8fec commit a107529
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 63 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,8 @@
"prettier --write",
"eslint --fix"
]
},
"dependencies": {
"tslx": "^0.1.0"
}
}
1 change: 1 addition & 0 deletions packages/hoci/src/components/selection/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const ModelValueSymbol = Symbol("[hi-selection]model-value");
export const ActiveClassSymbol: InjectionKey<Ref<ClassType>> = Symbol("[hi-selection]active-class");
export const ItemClassSymbol: InjectionKey<Ref<ClassType>> = Symbol("[hi-selection]item-class");
export const UnactiveSymbol: InjectionKey<Ref<ClassType>> = Symbol("[hi-selection]unactive-class");
export const DisabledClassSymbol: InjectionKey<Ref<ClassType>> = Symbol("[hi-selection]disabled-class");

export const ItemLabelSymbol: InjectionKey<MaybeRef<string | ((_: any) => ElementLike | null | undefined) | null | undefined>> = Symbol("[hi-selection]label");
export const ItemOptionsSymbol = Symbol("[hi-selection]options");
Expand Down
45 changes: 37 additions & 8 deletions packages/hoci/src/components/selection/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {
renderSlot,
watch
} from "vue";
import { cls } from "tslx";
import { defineHookComponent, defineHookProps } from "../../shared";
import type { ActivateEvent, ElementLike } from "../../types";
import { valuePropType } from "../../constants";
import {
ActivateEventSymbol,
ActiveClassSymbol,
ChangeActiveSymbol,
DisabledClassSymbol,
InitSymbol,
IsActiveSymbol,
ItemClassSymbol,
Expand Down Expand Up @@ -45,24 +47,31 @@ export const selectionItemProps = defineHookProps({
},
activateEvent: {
type: String as PropType<ActivateEvent>
},
disabled: {
type: Boolean,
default: false
}
});

export const useSelectionItem = defineHookComponent({
props: selectionItemProps,
setup(props, { slots }) {
const isActive = inject(IsActiveSymbol, () => false);
const isActiveFn = inject(IsActiveSymbol, () => false);
const changeActive = inject(ChangeActiveSymbol, () => {});

const parentLabel = toRef(inject(ItemLabelSymbol));

const activate = () => {
if (props.disabled) {
return;
}
changeActive(props.value);
};

function render() {
return renderSlot(slots, "default", {
active: isActive(props.value),
active: isActiveFn(props.value),
activate
}, () => {
let label = props.label ?? parentLabel.value;
Expand Down Expand Up @@ -92,17 +101,33 @@ export const useSelectionItem = defineHookComponent({
onDeactivated(() => remove());
}

const isActive = computed(() => isActiveFn(props.value));

const isDisabled = computed(() => props.disabled);

const activeClass = computed(
() => inject(ActiveClassSymbol)?.value ?? "active"
);
const unactiveClass = computed(
() => inject(UnactiveSymbol)?.value ?? "unactive"
);

const disabledClass = computed(() => {
return inject(DisabledClassSymbol)?.value ?? "disabled";
});

const itemClass = computed(() => {
return [inject(ItemClassSymbol)?.value ?? ""].concat(
isActive(props.value) ? activeClass.value : unactiveClass.value
);
return inject(ItemClassSymbol)?.value ?? "";
});

const className = computed(() => {
const array = [itemClass.value];
if (!isDisabled.value) {
array.push(isActiveFn(props.value) ? activeClass.value : unactiveClass.value);
} else {
array.push(disabledClass.value);
}
return cls(array);
});

const activateEvent = toRef(() => {
Expand All @@ -114,9 +139,12 @@ export const useSelectionItem = defineHookComponent({
activate,
render,
isActive,
isDisabled,
activeClass,
unactiveClass,
disabledClass,
itemClass,
className,
activateEvent
};
}
Expand All @@ -132,16 +160,17 @@ export const HiItem = defineComponent({
}
},
setup(props, context) {
const { render, activate, itemClass, activateEvent } = useSelectionItem(
const { render, activate, className, isDisabled, activateEvent } = useSelectionItem(
props,
context
);
return () =>
h(
props.tag,
{
class: itemClass.value,
[`on${capitalize(activateEvent.value)}`]: activate
class: className.value,
[`on${capitalize(activateEvent.value)}`]: activate,
disabled: isDisabled.value
},
render()
);
Expand Down
23 changes: 17 additions & 6 deletions packages/hoci/src/components/selection/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import {
reactive,
renderSlot
} from "vue";
import { cls } from "tslx";
import { type ActivateEvent, type ElementLike } from "../../types";
import { classPropType, labelPropType, valuePropType } from "../../constants";
import {
defineHookComponent,
defineHookEmits,
defineHookProps,
normalizeClass
defineHookProps
} from "../../shared";
import { type Option } from "./constants";
import { DisabledClassSymbol, type Option } from "./constants";
import {
ActivateEventSymbol,
ActiveClassSymbol,
Expand Down Expand Up @@ -48,6 +48,10 @@ export const selectionListProps = defineHookProps({
type: classPropType,
default: ""
},
disabledClass: {
type: classPropType,
default: "disabled"
},
unactiveClass: {
type: classPropType,
default: ""
Expand Down Expand Up @@ -128,24 +132,31 @@ export const useSelectionList = defineHookComponent({

provide(
ActiveClassSymbol,
computed(() => normalizeClass(props.activeClass))
computed(() => cls(props.activeClass))
);

provide(
UnactiveSymbol,
computed(() => normalizeClass(props.unactiveClass))
computed(() => cls(props.unactiveClass))
);

provide(
DisabledClassSymbol,
computed(() => cls(props.disabledClass))
);

provide(
ItemClassSymbol,
computed(() => normalizeClass(props.itemClass))
computed(() => cls(props.itemClass))
);

provide(
ItemLabelSymbol,
computed(() => props.label)
);



provide(
ActivateEventSymbol,
computed(() => props.activateEvent)
Expand Down
21 changes: 13 additions & 8 deletions packages/hoci/src/components/switch/switch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type PropType } from "vue";
import { capitalize, computed, defineComponent, h, renderSlot } from "vue";
import { useVModel } from "@vueuse/core";
import { cls } from "tslx";
import {
defineHookComponent,
defineHookEmits,
Expand Down Expand Up @@ -63,18 +64,21 @@ export const useSwitch = defineHookComponent({
}
};

const switchClass = computed(() => {
return [
const isDisabled = computed(() => props.disabled);

const className = computed(() => {
return cls([
props.class,
modelValue.value ? props.activeClass : props.unactiveClass,
props.disabled ? props.disabledClass : ""
];
isDisabled.value ? props.disabledClass : ""
]);
});

return {
toggle,
modelValue,
switchClass
className,
isDisabled
};
}
});
Expand All @@ -92,17 +96,18 @@ export const HiSwitch = defineComponent({

setup(props, context) {
const { slots } = context;
const { switchClass, toggle, modelValue } = useSwitch(props, context);
const { className, toggle, modelValue, isDisabled } = useSwitch(props, context);

return () => {
return h(
props.tag,
{
class: switchClass.value,
class: className.value,
[`on${capitalize(props.activateEvent)}`]: toggle
},
renderSlot(slots, "default", {
active: modelValue.value
active: modelValue.value,
isDisabled: isDisabled.value
})
);
};
Expand Down
12 changes: 0 additions & 12 deletions packages/hoci/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {
SetupContext
} from "vue";
import { reactiveComputed } from "@vueuse/core";
import type { ClassType } from "./types";

export interface HookComponentOptions<
R,
Expand Down Expand Up @@ -133,14 +132,3 @@ export function isExtends(types: PropType<any>, value: PropType<any>): boolean {
return value === types;
}

export function normalizeClass(value: ClassType): string {
if (Array.isArray(value)) {
return value.join(" ");
}
if (typeof value === "string") {
return value;
}
return Object.keys(value)
.filter((e) => !!value[e])
.join(" ");
}
19 changes: 15 additions & 4 deletions playground/src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { HiIcon, HiItem, HiSelection, HiSwitch } from "hoci";
import hociSvg from "./assets/hoci.svg";
export default defineComponent(() => {
const selectedIndex = ref(2);
const selectedIndex = ref<number[] | number>(2);
const logs = ref<string[]>([]);
const selectionState = reactive({
Expand Down Expand Up @@ -36,16 +36,27 @@ export default defineComponent(() => {
return () => {
return <div class="w-full p-4">
<HiIcon class="text-green rounded" width={48} height={48} src={hociSvg}/>
<HiSelection {...selectionState} activateEvent="click" onChange={handleChange} v-model={selectedIndex.value} tag="div" itemClass="duration-300 cursor-pointer px-2 py-1" class="flex space-x-4 items-center" activeClass="text-white bg-hex-f00">
<HiSelection {...selectionState}
activateEvent="click"
onChange={handleChange}
v-model={selectedIndex.value}
tag="div"
itemClass="duration-300 cursor-pointer px-2 py-1"
class="flex space-x-4 items-center"
activeClass="text-white bg-hex-f00"
disabledClass="bg-gray-200 cursor-not-allowed line-through text-gray-500"
>
<HiItem value={1}>Item 1</HiItem>
<HiItem value={2}>Item 2</HiItem>
<HiItem value={3}>Item 3</HiItem>
<HiItem disabled value={3}>Item 3</HiItem>
<HiItem value={4}>Item 4</HiItem>
<HiItem value={5}>Item 5</HiItem>
</HiSelection>
<div class="flex space-x-4 items-center">
<HiSwitch tag="span" v-model={selectionState.multiple} class="cursor-pointer mt-4 duration-200 select-none" activeClass="text-hex-f00">Multiple</HiSwitch>
<HiSwitch tag="span" v-model={selectionState.clearable} class="cursor-pointer mt-4 duration-200 select-none" activeClass="text-hex-f00">Clearable</HiSwitch>
</div>
<div>Selected:{selectedIndex.value}</div>
<div>Selected:{JSON.stringify(selectedIndex.value)}</div>
<div class="mt-4"></div>
<div class="flex justify-between items-center">
<div>Console: </div>
Expand Down
48 changes: 24 additions & 24 deletions playground/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
{
"compilerOptions": {
"baseUrl": "./",
"target": "esnext",
"module": "esnext",
"lib": ["esnext", "DOM"],
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"strictNullChecks": true,
"resolveJsonModule": true,
"skipDefaultLibCheck": true,
"outDir": "./dist",
"declaration": true,
"jsx": "preserve",
"paths": {
"@/*": ["src/*"],
"hoci":["../packages/hoci/src/index.ts"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
],
"compilerOptions": {
"baseUrl": "./",
"target": "esnext",
"module": "esnext",
"lib": ["esnext", "DOM"],
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"strictNullChecks": true,
"resolveJsonModule": true,
"skipDefaultLibCheck": true,
"outDir": "./dist",
"declaration": true,
"jsx": "preserve",
"paths": {
"@/*": ["src/*"],
"hoci": ["../packages/hoci/src/index.ts"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": ["node_modules", "dist"]
}
5 changes: 5 additions & 0 deletions playground/unocss.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from "unocss";

export default defineConfig({

});
2 changes: 1 addition & 1 deletion playground/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import path from "path";
import path from "node:path";
import vue from "@vitejs/plugin-vue";
import jsx from "@vitejs/plugin-vue-jsx";

Expand Down
Loading

0 comments on commit a107529

Please sign in to comment.