mirror of
https://github.com/directus/directus.git
synced 2026-02-16 13:14:55 -05:00
* Step 1 * Step 2 * False sense of confidence * Couple more before dinner * Update schema package * Update format-title * Upgrade specs file * Close * Replace ts-node-dev with tsx, and various others * Replace lodash with lodash-es * Add lodash-es types * Update knex import * More fun is had * FSE * Consolidate repos * Various tweaks and fixes * Fix specs * Remove dependency on knex-schema-inspector * Fix wrong imports of inspector * Move shared exceptions to new package * Move constants to separate module * Move types to new types package * Use directus/types * I believe this is no longer needed * [WIP] Start moving utils to esm * ESMify Shared * Move shared utils to @directus/utils * Use @directus/utils instead of @directus/shared/utils * It runs! * Use correct schemaoverview type * Fix imports * Fix the thing * Start on new update-checker lib * Use new update-check package * Swap out directus/shared in app * Pushing through the last bits now * Dangerously make extensions SDK ESM * Use @directus/types in tests * Copy util function to test * Fix linter config * Add missing import * Hot takes * Fix build * Curse these default exports * No tests in constants * Add tests * Remove tests from types * Add tests for exceptions * Fix test * Fix app tests * Fix import in test * Fix various tests * Fix specs export * Some more tests * Remove broken integration tests These were broken beyond repair.. They were also written before we really knew what we we're doing with tests, so I think it's better to say goodbye and start over with these * Regenerate lockfile * Fix imports from merge * I create my own problems * Make sharp play nice * Add vitest config * Install missing blackbox dep * Consts shouldn't be in types tsk tsk tsk tsk * Fix type/const usage in extensions-sdk * cursed.default * Reduce circular deps * Fix circular dep in items service * vvv * Trigger testing for all vendors * Add workaround for rollup * Prepend the file protocol for the ESM loader to be compatible with Windows "WARN: Only URLs with a scheme in: file and data are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'" * Fix postgres * Schema package updates Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> * Resolve cjs/mjs extensions * Clean-up eslint config * fixed extension concatination * using string interpolation for consistency * Revert MySQL optimisation * Revert testing for all vendors * Replace tsx with esbuild-kit/esm-loader Is a bit faster and we can rely on the built-in `watch` and `inspect` functionalities of Node.js Note: The possibility to watch other files (.env in our case) might be added in the future, see https://github.com/nodejs/node/issues/45467 * Use exact version for esbuild-kit/esm-loader * Fix import --------- Co-authored-by: ian <licitdev@gmail.com> Co-authored-by: Brainslug <tim@brainslug.nl> Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
241 lines
5.2 KiB
Vue
241 lines
5.2 KiB
Vue
<template>
|
|
<component
|
|
:is="customValue ? 'div' : 'button'"
|
|
class="v-checkbox"
|
|
type="button"
|
|
role="checkbox"
|
|
:aria-pressed="isChecked ? 'true' : 'false'"
|
|
:disabled="disabled"
|
|
:class="{ checked: isChecked, indeterminate, block }"
|
|
@click.stop="toggleInput"
|
|
>
|
|
<div v-if="$slots.prepend" class="prepend"><slot name="prepend" /></div>
|
|
<v-icon class="checkbox" :name="icon" :disabled="disabled" />
|
|
<span class="label type-text">
|
|
<slot v-if="customValue === false">{{ label }}</slot>
|
|
<input v-else v-model="internalValue" class="custom-input" />
|
|
</span>
|
|
<div v-if="$slots.append" class="append"><slot name="append" /></div>
|
|
</component>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
import { useSync } from '@directus/composables';
|
|
|
|
interface Props {
|
|
/** If the `modelValue` is an array of strings, activates the checkbox if the value is inside it */
|
|
value?: string | null;
|
|
/** Used to model the active state */
|
|
modelValue?: boolean | string[] | null;
|
|
/** Label for the checkbox */
|
|
label?: string | null;
|
|
/** Disable the checkbox */
|
|
disabled?: boolean;
|
|
/** Renders the checkbox neither selected nor unselected */
|
|
indeterminate?: boolean;
|
|
/** What icon to use for the on state */
|
|
iconOn?: string;
|
|
/** What icon to use for the off state */
|
|
iconOff?: string;
|
|
/** What icon to use for the indeterminate state */
|
|
iconIndeterminate?: string;
|
|
/** Show as styled block. Matches input size */
|
|
block?: boolean;
|
|
/** If a custom value can be entered next to it */
|
|
customValue?: boolean;
|
|
/** TODO: What the? */
|
|
checked?: boolean | null;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
value: null,
|
|
modelValue: null,
|
|
label: null,
|
|
disabled: false,
|
|
indeterminate: false,
|
|
iconOn: 'check_box',
|
|
iconOff: 'check_box_outline_blank',
|
|
iconIndeterminate: 'indeterminate_check_box',
|
|
block: false,
|
|
customValue: false,
|
|
checked: null,
|
|
});
|
|
|
|
const emit = defineEmits(['update:indeterminate', 'update:modelValue', 'update:value']);
|
|
|
|
const internalValue = useSync(props, 'value', emit);
|
|
|
|
const isChecked = computed<boolean>(() => {
|
|
if (props.checked !== null) return props.checked;
|
|
|
|
if (props.modelValue instanceof Array) {
|
|
if (!props.value) return false;
|
|
|
|
return props.modelValue.includes(props.value);
|
|
}
|
|
|
|
return props.modelValue === true;
|
|
});
|
|
|
|
const icon = computed<string>(() => {
|
|
if (props.indeterminate === true) return props.iconIndeterminate;
|
|
if (props.checked === null && props.modelValue === null) return props.iconIndeterminate;
|
|
|
|
return isChecked.value ? props.iconOn : props.iconOff;
|
|
});
|
|
|
|
function toggleInput(): void {
|
|
if (props.disabled) return;
|
|
|
|
if (props.indeterminate === true) {
|
|
emit('update:indeterminate', false);
|
|
}
|
|
|
|
if (props.modelValue instanceof Array && props.value) {
|
|
const newValue = [...props.modelValue];
|
|
|
|
if (props.modelValue.includes(props.value) === false) {
|
|
newValue.push(props.value);
|
|
} else {
|
|
newValue.splice(newValue.indexOf(props.value), 1);
|
|
}
|
|
|
|
emit('update:modelValue', newValue);
|
|
} else {
|
|
emit('update:modelValue', !props.modelValue);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
body {
|
|
--v-checkbox-color: var(--primary);
|
|
--v-checkbox-unchecked-color: var(--foreground-subdued);
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '@/styles/mixins/no-wrap';
|
|
|
|
.v-checkbox {
|
|
--v-icon-color: var(--v-checkbox-unchecked-color);
|
|
--v-icon-color-hover: var(--primary);
|
|
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 0;
|
|
text-align: left;
|
|
background-color: transparent;
|
|
border: none;
|
|
border-radius: 0;
|
|
appearance: none;
|
|
|
|
.label:not(:empty) {
|
|
flex-grow: 1;
|
|
margin-left: 8px;
|
|
transition: color var(--fast) var(--transition);
|
|
|
|
input {
|
|
width: 100%;
|
|
background-color: transparent;
|
|
border: none;
|
|
border-bottom: 2px solid var(--border-normal);
|
|
border-radius: 0;
|
|
}
|
|
|
|
@include no-wrap;
|
|
}
|
|
|
|
& .checkbox {
|
|
--v-icon-color: var(--v-checkbox-unchecked-color);
|
|
|
|
transition: color var(--fast) var(--transition);
|
|
}
|
|
|
|
&:disabled {
|
|
cursor: not-allowed;
|
|
|
|
.label {
|
|
color: var(--foreground-subdued);
|
|
}
|
|
|
|
.checkbox {
|
|
--v-icon-color: var(--foreground-subdued);
|
|
}
|
|
}
|
|
|
|
&.block {
|
|
position: relative;
|
|
width: 100%;
|
|
height: var(--input-height);
|
|
padding: 10px; // 14 - 4 (border)
|
|
background-color: var(--background-page);
|
|
border: var(--border-width) solid var(--border-normal);
|
|
border-radius: var(--border-radius);
|
|
transition: all var(--fast) var(--transition);
|
|
|
|
&:disabled {
|
|
background-color: var(--background-subdued);
|
|
}
|
|
|
|
&::before {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
z-index: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: var(--border-radius);
|
|
content: '';
|
|
}
|
|
|
|
> * {
|
|
z-index: 1;
|
|
}
|
|
}
|
|
|
|
&:not(:disabled):hover {
|
|
.checkbox {
|
|
--v-icon-color: var(--primary);
|
|
}
|
|
|
|
&.block {
|
|
background-color: var(--background-subdued);
|
|
border-color: var(--border-normal-alt);
|
|
}
|
|
}
|
|
|
|
&:not(:disabled):not(.indeterminate) {
|
|
.label {
|
|
color: var(--foreground-normal);
|
|
}
|
|
|
|
&.block {
|
|
&::before {
|
|
opacity: 0.1;
|
|
}
|
|
}
|
|
}
|
|
|
|
&:not(:disabled):not(.indeterminate).checked {
|
|
.checkbox {
|
|
--v-icon-color: var(--v-checkbox-color);
|
|
}
|
|
|
|
&.block {
|
|
.label {
|
|
color: var(--v-checkbox-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
.prepend,
|
|
.append {
|
|
display: contents;
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
</style>
|