Skip to content

Commit

Permalink
Color field: disable spectrum, merge pickerOptions, refactor (#4820)
Browse files Browse the repository at this point in the history
* merge pickerOptions with options, support disabling the spectrum, refactor

* cleanup
  • Loading branch information
stuartromanek authored Jan 6, 2025
1 parent 5e978e6 commit 07df805
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 106 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## UNRELEASED

### Fixes

* Fixes ability to change color hue by clicking the color hue bar rather than dragging the indicator
* Prevents the rich text control bar from closing while using certain UI within the color picker

### Adds

* Ability to disable the color spectrum UI of a color picker

### Changes

* The `pickerOptions` sub property of a color field's configuration has been merged with it's parent `options` object.

## 4.11.2 (2024-12-29)

### Fixes
Expand Down
14 changes: 13 additions & 1 deletion modules/@apostrophecms/color-field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ module.exports = {
self.name = self.options.name;
self.addFieldType();
self.enableBrowserData();
self.defaultOptions = {
format: 'hex8',
disableAlpha: false,
disableFields: false,
disableSpectrum: false,
presetColors: [
'#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321',
'#417505', '#BD10E0', '#9013FE', '#4A90E2', '#50E3C2',
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'
]
};
},
methods(self) {
return {
Expand All @@ -36,7 +47,8 @@ module.exports = {
getBrowserData(req) {
return {
name: self.name,
action: self.action
action: self.action,
defaultOptions: self.defaultOptions
};
}
};
Expand Down
87 changes: 66 additions & 21 deletions modules/@apostrophecms/color-field/ui/apos/components/AposColor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@
role="application"
aria-label="Color picker"
class="apos-color"
:class="[disableAlpha ? 'apos-color--disable-alpha' : '']"
:class="[
disableAlpha ? 'apos-color--disable-alpha' : null,
disableSpectrum ? 'apos-color--disable-spectrum' : null,
disableFields ? 'apos-color--disable-fields' : null,
!presetColors ? 'apos-color--disable-presets' : null
]"
>
<div class="apos-color__saturation-wrap">
<div v-if="!disableSpectrum" class="apos-color__saturation-wrap">
<Saturation :value="colors" @change="childChange" />
</div>
<div class="apos-color__controls">
<div
v-if="!(disableSpectrum && disableAlpha)"
class="apos-color__controls"
>
<div class="apos-color__sliders">
<div class="apos-color__hue-wrap">
<div v-if="!disableSpectrum" class="apos-color__hue-wrap">
<Hue :value="colors" @change="childChange" />
</div>
<div v-if="!disableAlpha" class="apos-color__alpha-wrap">
Expand Down Expand Up @@ -68,6 +76,7 @@
</div>
</div>
<div
v-if="presetColors"
class="apos-color__presets"
role="group"
aria-label="A color preset, pick one to set as current color"
Expand Down Expand Up @@ -103,12 +112,7 @@ import hue from '../lib/AposColorHue.vue';
import alpha from '../lib/AposColorAlpha.vue';
import checkboard from '../lib/AposColorCheckerboard.vue';
const presetColors = [
'#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321',
'#417505', '#BD10E0', '#9013FE', '#4A90E2', '#50E3C2',
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF',
'rgba(0,0,0,0)'
];
const defaultOptions = { ...apos.modules['@apostrophecms/color-field'].defaultOptions };
export default {
name: 'AposColor',
Expand All @@ -121,22 +125,57 @@ export default {
},
mixins: [ colorMixin ],
props: {
presetColors: {
type: Array,
options: {
type: Object,
default() {
return presetColors;
return defaultOptions;
}
},
disableAlpha: {
type: Boolean,
default: false
},
disableFields: {
type: Boolean,
default: false
}
},
computed: {
defaultOptions() {
return defaultOptions;
},
finalOptions() {
let final = { ...this.options };
// Handle BC `pickerOptions` sub object.
// Modern API wins out over BC conflicts
if (final.pickerOptions) {
final = {
...final.pickerOptions,
...final
};
delete final.pickerOptions;
}
// Normalize disabling presetColors
if (
Array.isArray(final.presetColors) &&
final.presetColors.length === 0
) {
final.presetColors = false;
}
// If `true`, let defaults through
if (final.presetColors === true) {
delete final.presetColors;
}
return Object.assign({ ...this.defaultOptions }, final);
},
presetColors() {
return this.finalOptions.presetColors;
},
disableAlpha() {
return this.finalOptions.disableAlpha;
},
disableSpectrum() {
return this.finalOptions.disableSpectrum;
},
disableFields() {
return this.finalOptions.disableFields;
},
hex() {
let hex;
if (this.colors.a < 1) {
Expand Down Expand Up @@ -201,6 +240,12 @@ export default {
box-shadow: 0 0 0 1px rgb(0 0 0 / 15%), 0 8px 16px rgb(0 0 0 / 15%);
}
.apos-color--disable-alpha.apos-color--disable-spectrum.apos-color--disable-fields {
.apos-color__presets {
border-top: none;
}
}
.apos-color__saturation-wrap {
position: relative;
overflow: hidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@close="close"
>
<AposColor
v-bind="pickerOptions"
:options="options"
:model-value="pickerValue"
@update:model-value="update"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="apos-color__hue" :class="[directionClass]">
<div
ref="container"
class="vc-hue-container"
class="apos-color__hue-container"
role="slider"
:aria-valuenow="colors.hsl.h"
aria-valuemin="0"
Expand Down
38 changes: 9 additions & 29 deletions modules/@apostrophecms/color-field/ui/apos/logic/AposInputColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,16 @@ export default {
data() {
return {
active: false,
tinyColorObj: null,
startsNull: false,
defaultFormat: 'hex8',
defaultPickerOptions: {
presetColors: [
'#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321',
'#417505', '#BD10E0', '#9013FE', '#4A90E2', '#50E3C2',
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'
],
disableAlpha: false,
disableFields: false
}
tinyColorObj: null
};
},
computed: {
// Color picker doesn't allow null or undefined values
pickerValue() {
return this.next || '';
return this.next || this.defaultValue;
},
// Color picker doesn't allow null or undefined values
defaultValue() {
return this.field.def || '';
},
buttonOptions() {
return {
Expand All @@ -38,16 +30,9 @@ export default {
color: this.modelValue.data || ''
};
},
format() {
return this.field.options && this.field.options.format
? this.field.options.format
: this.defaultFormat;
options() {
return this.field?.options || {};
},
pickerOptions() {
const fieldOptions = this.field.options?.pickerOptions || {};
return Object.assign(this.defaultPickerOptions, fieldOptions);
},

valueLabel() {
if (this.next) {
return this.next;
Expand Down Expand Up @@ -75,12 +60,7 @@ export default {
this.active = false;
},
update(value) {
this.tinyColorObj = new TinyColor(value.hsl);
if (value._cssVariable) {
this.next = value._cssVariable;
} else {
this.next = this.tinyColorObj.toString(this.format);
}
this.next = value;
},
validate(value) {
if (this.field.required) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,15 @@ export default {
return this.val;
},
set(newVal) {
let stringVal;
if (newVal._cssVariable) {
stringVal = newVal._cssVariable;
} else {
const colorObj = tinycolor(newVal.hsl);
stringVal = colorObj.toString(this.finalOptions.format);
}
this.val = newVal;
this.$emit('update:modelValue', newVal);
this.$emit('update:modelValue', stringVal);
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
@mousedown="handleMouseDown"
>
<AposColor
v-bind="pickerOptions"
:options="userOptions"
:model-value="pickerValue"
@update:model-value="update"
@focus="focus"
Expand All @@ -60,7 +60,6 @@
import {
ref, watch, computed, defineComponent
} from 'vue';
import { TinyColor } from '@ctrl/tinycolor';
export default defineComponent({
name: 'AposTiptapColor',
Expand Down Expand Up @@ -91,55 +90,20 @@ export default defineComponent({
setup(props) {
const active = ref(false);
const next = ref('');
const tinyColorObj = ref(null);
const startsNull = ref(false);
const indicatorColor = ref('#000000');
const defaultOptions = {
presetColors: [
'#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321',
'#417505', '#BD10E0', '#9013FE', '#4A90E2', '#50E3C2',
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'
],
disableAlpha: false,
disableFields: false,
format: 'hex8'
};
const projectOptions = computed(() => {
return window.apos.modules['@apostrophecms/rich-text-widget'];
});
const areaOptions = props.options || {};
const userOptions = computed(() => {
return {
const options = {
...projectOptions.value,
...areaOptions
};
});
const mergedOptions = computed(() => {
return {
...defaultOptions,
...userOptions.value.color
};
});
const pickerOptions = computed(() => {
const {
presetColors, disableAlpha, disableFields
} = mergedOptions.value;
return {
presetColors,
disableAlpha,
disableFields
};
});
const format = computed(() => {
return mergedOptions.value.format;
return options.color;
});
const pickerValue = ref(next.value || '');
Expand Down Expand Up @@ -177,16 +141,8 @@ export default defineComponent({
};
const update = (value) => {
let color;
if (value._cssVariable) {
next.value = value._cssVariable;
color = `var(${next.value})`;
} else {
tinyColorObj.value = new TinyColor(value.hsl);
next.value = tinyColorObj.value.toString(format.value);
color = next.value;
}
props.editor.chain().focus().setColor(color).run();
next.value = value;
props.editor.chain().focus().setColor(value).run();
indicatorColor.value = next.value;
};
Expand All @@ -201,7 +157,11 @@ export default defineComponent({
const handleMouseDown = (event) => {
const target = event.target;
if (target.closest('.apos-color__saturation-wrap') || target.closest('.apos-color__presets')) {
if (
target.closest('.apos-color__saturation-wrap') ||
target.closest('.apos-color__presets') ||
target.closest('.apos-color__controls')
) {
event.preventDefault();
} else {
props.editor.view.dom.focus();
Expand All @@ -211,10 +171,9 @@ export default defineComponent({
return {
active,
indicatorColor,
pickerOptions,
userOptions,
pickerValue,
hasSelection,
startsNull,
open,
close,
update,
Expand Down

0 comments on commit 07df805

Please sign in to comment.