- Add headless PropertySection and accessible SegmentedControl anatomy - Make PropertyList controlled and exactly typed with an undo-aware editor adapter - Consolidate SDK metadata loaders and link untranslated docs to canonical pages
115 lines
4 KiB
Vue
115 lines
4 KiB
Vue
<script setup lang="ts">
|
|
import { useFillControls, useOkHCL, useI18n, inputValue } from '@open-pencil/vue'
|
|
import { colorToHexRaw, parseColor } from '@open-pencil/core/color'
|
|
|
|
import FillPicker from '@/components/fill-picker/FillPicker.vue'
|
|
import PropertyListRoot from '@/components/properties/PropertyListRoot.vue'
|
|
import IconButton from '@/components/ui/IconButton.vue'
|
|
import PanelSection from '@/components/ui/panel/PanelSection.vue'
|
|
import ColorStyleRow from '@/components/properties/ColorStyleRow.vue'
|
|
import {
|
|
boundVariableSwatchBackground,
|
|
displayFillWithBoundVariable
|
|
} from '@/components/properties/color-style-row'
|
|
import { fillLabel } from '@/components/properties/fill-label'
|
|
import { createFillOkhclAdapter } from '@/components/properties/fill-okhcl'
|
|
|
|
import type { Fill, SceneNode } from '@open-pencil/scene-graph'
|
|
|
|
const fillCtx = useFillControls()
|
|
const okhcl = useOkHCL()
|
|
const { panels } = useI18n()
|
|
|
|
function updateFill(
|
|
activeNode: SceneNode | null | undefined,
|
|
index: number,
|
|
fill: Fill,
|
|
update: (index: number, fill: Fill) => void
|
|
) {
|
|
if (activeNode && fillCtx.getBoundVariable(activeNode.id, index)) {
|
|
fillCtx.unbindVariable(activeNode.id, index)
|
|
}
|
|
update(index, fill)
|
|
}
|
|
|
|
function updateFillHex(
|
|
activeNode: SceneNode | null | undefined,
|
|
index: number,
|
|
fill: Fill,
|
|
hex: string,
|
|
update: (index: number, fill: Fill) => void
|
|
) {
|
|
if (fill.type !== 'SOLID') return
|
|
const parsed = parseColor(hex.startsWith('#') ? hex : `#${hex}`)
|
|
if (!parsed) return
|
|
updateFill(activeNode, index, { ...fill, color: { ...parsed, a: fill.color.a } }, update)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<PropertyListRoot
|
|
v-slot="{ items, isMixed, activeNode, actions }"
|
|
prop-key="fills"
|
|
:label="panels.fill"
|
|
>
|
|
<PanelSection :label="panels.fill" data-test-id="fill-section">
|
|
<template #actions>
|
|
<IconButton
|
|
:label="panels.addFill"
|
|
data-test-id="fill-section-add"
|
|
@click="actions.add({ ...fillCtx.defaultFill })"
|
|
>
|
|
<icon-lucide-plus class="size-3.5" />
|
|
</IconButton>
|
|
</template>
|
|
<p v-if="isMixed" class="text-[11px] text-muted">{{ panels.mixedFillsHelp }}</p>
|
|
<ColorStyleRow
|
|
v-for="(fill, i) in items"
|
|
:key="`${i}:${fill.visible ? 'visible' : 'hidden'}`"
|
|
:item="fill"
|
|
:index="i"
|
|
:active-node-id="activeNode?.id ?? null"
|
|
:binding-api="fillCtx"
|
|
:variable-color="fill.type === 'SOLID' ? fill.color : undefined"
|
|
data-test-id="fill-item"
|
|
:data-test-index="i"
|
|
:remove-label="panels.removeFill"
|
|
@patch="actions.patch(i, $event)"
|
|
@toggle-visibility="actions.toggleVisibility(i)"
|
|
@remove="actions.remove(i)"
|
|
>
|
|
<FillPicker
|
|
:fill="activeNode ? displayFillWithBoundVariable(fillCtx, activeNode.id, i, fill) : fill"
|
|
:okhcl="createFillOkhclAdapter(okhcl, activeNode, i)"
|
|
:swatch-background="
|
|
activeNode ? boundVariableSwatchBackground(fillCtx, activeNode.id, i) : undefined
|
|
"
|
|
@update="updateFill(activeNode, i, $event, actions.update)"
|
|
/>
|
|
|
|
<input
|
|
v-if="
|
|
fill.type === 'SOLID' && !(activeNode && fillCtx.getBoundVariable(activeNode.id, i))
|
|
"
|
|
data-test-id="fill-hex-input"
|
|
class="min-w-0 flex-1 border-none bg-transparent font-mono text-xs text-surface outline-none"
|
|
:value="colorToHexRaw(fill.color)"
|
|
maxlength="6"
|
|
@change="updateFillHex(activeNode, i, fill, inputValue($event), actions.update)"
|
|
/>
|
|
<span
|
|
v-else
|
|
class="min-w-0 flex-1 truncate font-mono text-xs"
|
|
:class="
|
|
activeNode && fillCtx.getBoundVariable(activeNode.id, i)
|
|
? 'rounded bg-violet-500/10 px-1 text-violet-400'
|
|
: 'text-surface'
|
|
"
|
|
>
|
|
{{ fillLabel(fill, activeNode ? fillCtx.getBoundVariable(activeNode.id, i) : undefined) }}
|
|
</span>
|
|
</ColorStyleRow>
|
|
</PanelSection>
|
|
</PropertyListRoot>
|
|
</template>
|