@dou-ui/pivot 0.0.0-stage → 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/assets/default-PXde2wzm.js.map +1 -0
- package/dist/core/format.js +116 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/labels.js +28 -0
- package/dist/core/labels.js.map +1 -0
- package/dist/core/layout.js +190 -0
- package/dist/core/layout.js.map +1 -0
- package/dist/core/source.js +46 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/table.js +154 -0
- package/dist/core/table.js.map +1 -0
- package/dist/engine/aggregate.js +51 -0
- package/dist/engine/aggregate.js.map +1 -0
- package/dist/engine/compute.js +735 -0
- package/dist/engine/compute.js.map +1 -0
- package/dist/engine/engine.js +46 -0
- package/dist/engine/engine.js.map +1 -0
- package/dist/engine/formula.js +225 -0
- package/dist/engine/formula.js.map +1 -0
- package/dist/engine/group.js +107 -0
- package/dist/engine/group.js.map +1 -0
- package/dist/engine/hash.js +108 -0
- package/dist/engine/hash.js.map +1 -0
- package/dist/engine/index.js +8 -0
- package/dist/engine/show.js +132 -0
- package/dist/engine/show.js.map +1 -0
- package/dist/engine/source.js +339 -0
- package/dist/engine/source.js.map +1 -0
- package/dist/engine/tree.js +226 -0
- package/dist/engine/tree.js.map +1 -0
- package/dist/fields/fields.js +6 -0
- package/dist/fields/fields.js.map +1 -0
- package/dist/fields/fields.vue_vue_type_script_setup_true_lang.js +881 -0
- package/dist/fields/fields.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/fields/filter-list.js +6 -0
- package/dist/fields/filter-list.js.map +1 -0
- package/dist/fields/filter-list.vue_vue_type_script_setup_true_lang.js +184 -0
- package/dist/fields/filter-list.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/fields/formula-dialog.js +6 -0
- package/dist/fields/formula-dialog.js.map +1 -0
- package/dist/fields/formula-dialog.vue_vue_type_script_setup_true_lang.js +165 -0
- package/dist/fields/formula-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/fields/model.js +200 -0
- package/dist/fields/model.js.map +1 -0
- package/dist/fields/top-dialog.js +6 -0
- package/dist/fields/top-dialog.js.map +1 -0
- package/dist/fields/top-dialog.vue_vue_type_script_setup_true_lang.js +174 -0
- package/dist/fields/top-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.js +508 -0
- package/dist/locale.js.map +1 -0
- package/dist/pivot.js +6 -0
- package/dist/pivot.js.map +1 -0
- package/dist/pivot.vue_vue_type_script_setup_true_lang.js +1711 -0
- package/dist/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +13 -0
- package/dist/types/core/format.d.ts +26 -0
- package/dist/types/core/labels.d.ts +14 -0
- package/dist/types/core/layout.d.ts +72 -0
- package/dist/types/core/source.d.ts +7 -0
- package/dist/types/core/table.d.ts +73 -0
- package/dist/types/engine/aggregate.d.ts +35 -0
- package/dist/types/engine/compute.d.ts +173 -0
- package/dist/types/engine/engine.d.ts +29 -0
- package/dist/types/engine/formula.d.ts +44 -0
- package/dist/types/engine/group.d.ts +34 -0
- package/dist/types/engine/hash.d.ts +36 -0
- package/dist/types/engine/index.d.ts +15 -0
- package/dist/types/engine/show.d.ts +27 -0
- package/dist/types/engine/source.d.ts +108 -0
- package/dist/types/engine/tree.d.ts +87 -0
- package/dist/types/engine/types.d.ts +148 -0
- package/dist/types/fields/fields.vue.d.ts +26 -0
- package/dist/types/fields/filter-list.vue.d.ts +20 -0
- package/dist/types/fields/formula-dialog.vue.d.ts +30 -0
- package/dist/types/fields/model.d.ts +52 -0
- package/dist/types/fields/top-dialog.vue.d.ts +25 -0
- package/dist/types/index.d.ts +458 -0
- package/dist/types/locale.d.ts +184 -0
- package/dist/types/pivot.vue.d.ts +29 -0
- package/dist/types/types.d.ts +199 -0
- package/dist/types/worker/client.d.ts +19 -0
- package/dist/types/worker/default.d.ts +1 -0
- package/dist/types/worker/index.d.ts +5 -0
- package/dist/types/worker/protocol.d.ts +60 -0
- package/dist/types/worker/serve.d.ts +22 -0
- package/dist/worker/client.js +191 -0
- package/dist/worker/client.js.map +1 -0
- package/dist/worker/default.js +20 -0
- package/dist/worker/default.js.map +1 -0
- package/dist/worker/index.js +3 -0
- package/dist/worker/serve.js +101 -0
- package/dist/worker/serve.js.map +1 -0
- package/package.json +64 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_unref","_createBlock","_withCtx","_createVNode","_createTextVNode","_toDisplayString","_createCommentVNode","_resolveDynamicComponent","_mergeProps","_createElementVNode","_Fragment","_renderList","FilterList","FormulaDialog","TopDialog"],"sources":["../../src/fields/fields.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"Row = Record<string, unknown>\">\nimport type { HTMLAttributes } from 'vue'\nimport type { ForwardedAttributes } from 'dou-ui'\nimport {\n DouButton,\n DouCheckbox,\n DouDrawer,\n DouDropdown,\n DouDropdownItem,\n DouDropdownRadioGroup,\n DouDropdownSub,\n DouInput,\n DouPopover,\n DouSortable,\n useBreakpoints,\n} from 'dou-ui'\nimport {\n CalendarIcon,\n ChevronDownIcon,\n FilterIcon,\n HashIcon,\n LayoutThreeColumnsIcon,\n LayoutThreeRowsIcon,\n PlusIcon,\n SearchIcon,\n SigmaIcon,\n TablePivotIcon,\n ToggleLeftIcon,\n TypeIcon,\n} from '@dou-ui/icons'\nimport { computed, nextTick, onMounted, ref, useId, type Component } from 'vue'\nimport {\n resolveConfig,\n type PivotAggregator,\n type PivotResolvedField,\n type PivotShowAs,\n type PivotSource,\n} from '../engine'\nimport { BUILTIN_AGGREGATORS } from '../engine/aggregate'\nimport { DATE_PERIODS, groupKey, type PivotGroupBy } from '../engine/group'\nimport type { PivotConfig, PivotDimension, PivotFieldType, PivotFilter } from '../engine/types'\nimport { valueLabel } from '../core/labels'\nimport { usePivotSource } from '../core/source'\nimport { format, usePivotMessages } from '../locale'\nimport type { PivotFieldsProps } from '../types'\nimport FilterList from './filter-list.vue'\nimport FormulaDialog from './formula-dialog.vue'\nimport TopDialog from './top-dialog.vue'\nimport {\n areasOf,\n AREAS,\n configOf,\n isFiltering,\n moveItem,\n stepsFor,\n withAggregate,\n withDimension,\n withFilter,\n withRank,\n withValue,\n type PivotArea,\n type PivotAreas,\n type PivotFieldItem,\n type PivotRank,\n} from './model'\n\ndefineOptions({ name: 'DouPivotFields' })\n\nconst props = withDefaults(\n defineProps<\n PivotFieldsProps<Row> &\n /* @vue-ignore */ ForwardedAttributes<HTMLAttributes, PivotFieldsProps<Row>>\n >(),\n { drawer: 'auto' },\n)\nconst config = defineModel<PivotConfig>('config', { default: () => ({}) })\n\nconst messages = usePivotMessages(() => props.messages)\nconst source = usePivotSource(\n () => props.data,\n () => props.fields,\n)\nconst group = `dou-pivot-fields-${useId()}`\n\n// ---- the fields ----\n\nconst TYPE_ICON: Record<PivotFieldType, Component> = {\n string: TypeIcon,\n number: HashIcon,\n date: CalendarIcon,\n boolean: ToggleLeftIcon,\n}\nconst AREA_ICON: Record<PivotArea, Component> = {\n filters: FilterIcon,\n columns: LayoutThreeColumnsIcon,\n rows: LayoutThreeRowsIcon,\n values: SigmaIcon,\n}\n\nconst allFields = computed<PivotResolvedField<unknown>[]>(() => {\n const s = source.value\n // the source knows each listed field, and makes one up for any other key the config names\n return [...s.fields.values()] as PivotResolvedField<unknown>[]\n})\nconst field = (name: string) => source.value.field(name) as PivotResolvedField<unknown>\n\nconst query = ref('')\nconst listItems = computed<PivotFieldItem[]>({\n get: () => {\n const q = query.value.trim().toLocaleLowerCase()\n return allFields.value\n .filter((f) => !q || f.label.toLocaleLowerCase().includes(q) || f.name.includes(q))\n .map((f, index): PivotFieldItem => ({\n key: `l:${f.name}`,\n kind: 'field',\n field: f.name,\n index,\n }))\n },\n // the list always shows every field: dragging one out copies it\n set: () => {},\n})\n\nconst areas = computed(() => areasOf(config.value))\nconst used = computed(() => {\n const set = new Set<string>()\n for (const area of AREAS) for (const item of areas.value[area]) set.add(item.field)\n return set\n})\n\n// ---- moving fields ----\n\nlet pending: PivotAreas | null = null\n/** One drop updates two lists (the one left and the one entered); both land in one change. */\nfunction setArea(area: PivotArea, items: PivotFieldItem[]) {\n if (!pending) {\n pending = { ...areas.value }\n queueMicrotask(() => {\n const next = pending!\n pending = null\n config.value = configOf(next, config.value)\n })\n }\n pending[area] = items\n}\n\nconst areaModel = (area: PivotArea) =>\n computed<PivotFieldItem[]>({\n get: () => areas.value[area],\n set: (items) => setArea(area, items),\n })\nconst models = Object.fromEntries(AREAS.map((a) => [a, areaModel(a)])) as Record<\n PivotArea,\n ReturnType<typeof areaModel>\n>\n\nconst areaOf = (item: PivotFieldItem): PivotArea | null =>\n AREAS.find((a) => areas.value[a].some((i) => i.key === item.key)) ?? null\n\nfunction moveTo(item: PivotFieldItem, to: PivotArea | null) {\n config.value = configOf(moveItem(areas.value, areaOf(item), item, to), config.value)\n}\n\n/** Moves an item one place up or down in its area. */\nfunction shift(item: PivotFieldItem, by: -1 | 1) {\n const area = areaOf(item)\n if (!area) return\n const list = [...areas.value[area]]\n const at = list.findIndex((i) => i.key === item.key)\n const to = at + by\n if (to < 0 || to >= list.length) return\n list.splice(at, 1)\n list.splice(to, 0, item)\n config.value = configOf({ ...areas.value, [area]: list }, config.value)\n}\nconst placeOf = (item: PivotFieldItem) => {\n const area = areaOf(item)\n const list = area ? areas.value[area] : []\n return { first: list[0]?.key === item.key, last: list[list.length - 1]?.key === item.key }\n}\n\n/** The checkbox in the list: adds a field where it fits (numbers to the values), or takes it out everywhere. */\nfunction toggleField(name: string, on: boolean) {\n if (!on) {\n let next = areas.value\n for (const area of AREAS) next = { ...next, [area]: next[area].filter((i) => i.field !== name) }\n config.value = configOf(next, config.value)\n return\n }\n const item: PivotFieldItem = { key: `l:${name}`, kind: 'field', field: name, index: 0 }\n moveTo(item, field(name).type === 'number' ? 'values' : 'rows')\n}\n\nconst itemLabel = (item: PivotFieldItem) => (item.field ? field(item.field).label : '')\n\n// ---- what each chip shows ----\n\nconst resolved = computed(() => {\n try {\n return resolveConfig(source.value as never, config.value, { aggregators: aggregatorMap.value })\n } catch {\n return null\n }\n})\nconst aggregatorMap = computed(() => {\n const map: Record<string, PivotAggregator> = {}\n for (const a of props.aggregators ?? []) map[a.name] = a\n return map\n})\n\n/** How a grouping reads, as in the grouping menu. */\nfunction groupText(by: PivotGroupBy) {\n const m = messages.value.fields\n if (typeof by === 'string') return m.periods[by]\n const write = new Intl.NumberFormat(undefined, { maximumFractionDigits: 6 })\n return format(m.step, { step: write.format(by.step) })\n}\n\n/** A chip's grouping, shown apart from its name so it can go on a line of its own. */\nfunction chipGroup(item: PivotFieldItem) {\n if (item.kind !== 'dimension') return ''\n const by = dimensionOf(axisOf(item), item.field)?.by\n const top = topText(item.field)\n return [by === undefined ? '' : groupText(by), top].filter(Boolean).join(' · ')\n}\n\n/** How a field's top N or range reads (\"前 10 项\", \"合计 ≥ 100\"), or ''. */\nfunction topText(name: string) {\n const filter = filterOf(name)\n const m = messages.value.fields\n if (filter?.top) {\n return format(filter.top.order === 'asc' ? m.bottomN : m.topN, { count: filter.top.count })\n }\n if (filter?.between) {\n const write = new Intl.NumberFormat(undefined, { maximumFractionDigits: 6 })\n const { min, max } = filter.between\n const range =\n min !== undefined && max !== undefined\n ? format(messages.value.rangeLabel, { from: write.format(min), to: write.format(max) })\n : min !== undefined\n ? `≥ ${write.format(min)}`\n : `≤ ${write.format(max ?? 0)}`\n return format(m.between, { range })\n }\n return ''\n}\n\nconst chipName = (item: PivotFieldItem) =>\n item.kind === 'dimension' ? itemLabel(item) : chipText(item)\n\nfunction chipText(item: PivotFieldItem) {\n if (item.kind === 'dimension') {\n const extra = chipGroup(item)\n return extra\n ? format(messages.value.fields.grouped, { field: itemLabel(item), group: extra })\n : itemLabel(item)\n }\n if (item.kind !== 'value') return itemLabel(item)\n const value = resolved.value?.values[item.index]\n const given = config.value.values?.[item.index]\n if (!value) return item.field ? itemLabel(item) : messages.value.aggregates.count!\n return valueLabel(value, typeof given === 'object' ? given.label : undefined, messages.value)\n}\n\nconst dimensionOf = (axis: 'rows' | 'columns', name: string) => {\n const d = (config.value[axis] ?? []).find((x) => (typeof x === 'string' ? x : x.field) === name)\n return (typeof d === 'string' ? { field: d } : d) as Exclude<PivotDimension, string> | undefined\n}\n\nconst filterOf = (name: string) => config.value.filters?.[name]\n\n/** Whether a field's values can be filtered from its chip (not a value: it sums the field up). */\nconst canFilter = (item: PivotFieldItem) => item.kind !== 'value' && !!item.field\n\n// ---- the menus ----\n\nconst aggregatesFor = (name: string) => {\n const type = name ? field(name).type : 'string'\n const builtIn =\n type === 'number'\n ? ['sum', 'count', 'avg', 'min', 'max', 'distinct', 'median']\n : type === 'date'\n ? ['count', 'distinct', 'min', 'max']\n : ['count', 'distinct']\n const custom = (props.aggregators ?? [])\n .filter((a) => type === 'number' || a.input === 'value')\n .map((a) => a.name)\n return [...builtIn, ...custom.filter((n) => !builtIn.includes(n))]\n}\nconst aggregateText = (name: string) =>\n messages.value.aggregates[name] ??\n aggregatorMap.value[name]?.label ??\n BUILTIN_AGGREGATORS[name]?.label ??\n name\n\nconst currentAggregate = (index: number) => resolved.value?.values[index]?.aggregate ?? 'count'\n\n/** The groupings a field offers: periods for dates, round range sizes for numbers. */\nfunction groupingsFor(name: string): { key: string; by: PivotGroupBy | null; text: string }[] {\n const f = field(name)\n const m = messages.value.fields\n const none = { key: '', by: null, text: m.noGroup }\n if (f.type === 'date')\n return [none, ...DATE_PERIODS.map((p) => ({ key: p, by: p, text: m.periods[p] }))]\n if (f.type !== 'number') return []\n const measure = source.value.measure(name)\n let min = Infinity\n let max = -Infinity\n for (let i = 0; i < measure.length; i++) {\n const v = measure[i]!\n if (v < min) min = v\n if (v > max) max = v\n }\n const write = new Intl.NumberFormat(undefined, { maximumFractionDigits: 6 })\n return [\n none,\n ...stepsFor(min, max).map((step) => ({\n key: groupKey({ step }),\n by: { step },\n text: format(m.step, { step: write.format(step) }),\n })),\n ]\n}\n\n/** The sort a row field's menu shows: by its labels, or the rows by a value's grand total. */\nfunction sortKey(axis: 'rows' | 'columns', name: string) {\n const sort = config.value.sort\n if (axis === 'rows' && sort && !sort.column?.length) return `v:${sort.valueIndex}:${sort.order}`\n return dimensionOf(axis, name)?.sort ?? 'asc'\n}\nfunction onSort(axis: 'rows' | 'columns', name: string, key: string | number) {\n const by = /^v:(\\d+):(asc|desc)$/.exec(String(key))\n if (by) {\n const order = by[2] as 'asc' | 'desc'\n config.value = { ...config.value, sort: { valueIndex: +by[1]!, column: [], order } }\n return\n }\n const next = withDimension(config.value, axis, name, { sort: key as 'asc' | 'desc' })\n // sorting by labels on the rows takes over from sorting by a value\n if (axis === 'rows') next.sort = null\n config.value = next\n}\nfunction onGroup(axis: 'rows' | 'columns', name: string, key: string | number) {\n const option = groupingsFor(name).find((g) => g.key === key)\n if (!option) return\n config.value = withDimension(config.value, axis, name, { by: option.by })\n}\nfunction onSubtotal(axis: 'rows' | 'columns', name: string, on: boolean) {\n config.value = withDimension(config.value, axis, name, { subtotal: on })\n}\nfunction onAggregate(index: number, name: string | number) {\n config.value = withAggregate(config.value, index, String(name))\n}\n\n// ---- showing values ----\n\nconst SHOWS: PivotShowAs[] = [\n 'percentOfTotal',\n 'percentOfRow',\n 'percentOfColumn',\n 'percentOfParent',\n 'difference',\n 'percentDifference',\n 'runningTotal',\n 'rank',\n]\nconst valueSpec = (index: number) => {\n const v = config.value.values?.[index]\n return typeof v === 'object' ? v : undefined\n}\nconst showKey = (index: number) => {\n const show = valueSpec(index)?.show\n return show === undefined ? '' : typeof show === 'string' ? show : show.as\n}\nfunction onShow(index: number, key: string | number) {\n const spec = valueSpec(index)?.show\n const axis = typeof spec === 'object' ? spec.axis : undefined\n const show = key === '' ? null : axis ? { as: key as PivotShowAs, axis } : (key as PivotShowAs)\n config.value = withValue(config.value, index, { show: show as PivotShowAs | null })\n}\nconst markKey = (index: number) => {\n const mark = valueSpec(index)?.mark\n return mark === undefined ? '' : typeof mark === 'string' ? mark : mark.type\n}\nfunction onMark(index: number, key: string | number) {\n config.value = withValue(config.value, index, {\n mark: key === '' ? null : (key as 'bar' | 'scale'),\n })\n}\n\n// ---- top N ----\n\nconst TOPS = [\n { key: 't5', count: 5, order: 'desc' },\n { key: 't10', count: 10, order: 'desc' },\n { key: 't20', count: 20, order: 'desc' },\n { key: 'b5', count: 5, order: 'asc' },\n { key: 'b10', count: 10, order: 'asc' },\n] as const\nfunction topKey(name: string) {\n const filter = filterOf(name)\n if (filter?.between) return 'range'\n if (!filter?.top) return ''\n return `${filter.top.order === 'asc' ? 'b' : 't'}${filter.top.count}`\n}\nconst topOptions = (name: string) => {\n const m = messages.value.fields\n const options: { key: string; text: string }[] = [{ key: '', text: m.noTop }]\n for (const t of TOPS) {\n options.push({\n key: t.key,\n text: format(t.order === 'asc' ? m.bottomN : m.topN, { count: t.count }),\n })\n }\n // a top N or a range set elsewhere, which the list does not offer\n const key = topKey(name)\n if (key && !options.some((o) => o.key === key)) options.push({ key, text: topText(name) })\n return options\n}\nfunction onTop(item: PivotFieldItem, key: string | number) {\n if (key === 'range') return\n const match = /^([tb])(\\d+)$/.exec(String(key))\n const old = filterOf(item.field)?.top\n setRank(\n item,\n match\n ? {\n top: {\n ...(old?.valueIndex ? { valueIndex: old.valueIndex } : {}),\n count: Number(match[2]),\n ...(match[1] === 'b' ? { order: 'asc' as const } : {}),\n },\n }\n : null,\n )\n}\nfunction setRank(item: PivotFieldItem, rank: PivotRank | null) {\n config.value = withRank(config.value, item.field, rank, item.kind === 'filter')\n}\n\n/** The field whose top N or range is set in the dialog. */\nconst topItem = ref<PivotFieldItem | null>(null)\nconst topOpen = ref(false)\nfunction openTop(item: PivotFieldItem) {\n topItem.value = item\n // after the menu has closed and given focus back\n nextTick(() => (topOpen.value = true))\n}\n\n// ---- calculated values ----\n\nconst formulaOpen = ref(false)\n/** The value being changed in the dialog, or -1 for a new one. */\nconst formulaIndex = ref(-1)\nconst formulaInitial = computed(() => {\n const spec = formulaIndex.value >= 0 ? valueSpec(formulaIndex.value) : undefined\n return spec?.formula === undefined ? null : { formula: spec.formula, label: spec.label }\n})\nfunction openFormula(index: number) {\n formulaIndex.value = index\n // after a menu has closed and given focus back\n nextTick(() => (formulaOpen.value = true))\n}\nfunction applyFormula(value: { formula: string; label?: string }) {\n const index = formulaIndex.value\n if (index < 0) {\n config.value = { ...config.value, values: [...(config.value.values ?? []), value] }\n return\n }\n config.value = withValue(config.value, index, {\n formula: value.formula,\n label: value.label ?? null,\n })\n}\nconst isFormula = (item: PivotFieldItem) =>\n item.kind === 'value' && valueSpec(item.index)?.formula !== undefined\n\n// ---- filters ----\n\nconst filterOpen = ref<string | null>(null)\nfunction setFilterOpen(key: string, open: boolean) {\n if (open) filterOpen.value = key\n else if (filterOpen.value === key) filterOpen.value = null\n}\nfunction openFilter(item: PivotFieldItem) {\n // after the menu has closed and given focus back\n nextTick(() => (filterOpen.value = item.key))\n}\nconst filterBy = (item: PivotFieldItem): PivotGroupBy | undefined => {\n if (item.kind === 'dimension') {\n const axis = areas.value.rows.some((i) => i.key === item.key) ? 'rows' : 'columns'\n return dimensionOf(axis, item.field)?.by\n }\n return filterOf(item.field)?.by\n}\nfunction applyFilter(item: PivotFieldItem, filter: PivotFilter | null) {\n // the list sets which groups are picked; top N and ranges stay\n const old = filterOf(item.field)\n const kept = { top: old?.top, between: old?.between }\n if (kept.top || kept.between) {\n filter = {\n ...filter,\n ...(kept.top ? { top: kept.top } : {}),\n ...(kept.between ? { between: kept.between } : {}),\n }\n if (filter.by === undefined && old?.by !== undefined) filter.by = old.by\n }\n config.value = withFilter(config.value, item.field, filter, item.kind === 'filter')\n filterOpen.value = null\n}\n\n// ---- a narrow screen ----\n\nconst breakpoints = useBreakpoints()\nconst mounted = ref(false)\nonMounted(() => (mounted.value = true))\nconst inDrawer = computed(() =>\n props.drawer === 'auto' ? mounted.value && !breakpoints.sm : props.drawer,\n)\nconst drawerOpen = ref(false)\n\nconst areaTitle = (area: PivotArea) => messages.value.fields.areas[area]\n/** Where else an item can go; a count of records has no field to group or filter by. */\nconst otherAreas = (item: PivotFieldItem) => {\n const here = areaOf(item)\n return AREAS.filter((a) => a !== here && (item.field || a === 'values'))\n}\nconst axisOf = (item: PivotFieldItem) =>\n areas.value.rows.some((i) => i.key === item.key) ? ('rows' as const) : ('columns' as const)\n\nconst filtered = (item: PivotFieldItem) => isFiltering(filterOf(item.field))\n</script>\n\n<template>\n <div\n :class=\"inDrawer ? 'dou-pivot-fields-trigger' : 'dou-pivot-fields'\"\n :role=\"inDrawer ? undefined : 'region'\"\n :aria-label=\"inDrawer ? undefined : messages.fields.panel\"\n >\n <DouButton v-if=\"inDrawer\" size=\"sm\" variant=\"outline\" @click=\"drawerOpen = true\">\n <template #leading><TablePivotIcon aria-hidden=\"true\" /></template>\n {{ messages.fields.open }}\n </DouButton>\n <component\n :is=\"inDrawer ? DouDrawer : 'div'\"\n v-bind=\"\n inDrawer\n ? { open: drawerOpen, title: messages.fields.panel, placement: 'bottom', size: '80%' }\n : { class: 'dou-pivot-fields__inner' }\n \"\n @update:open=\"drawerOpen = $event\"\n >\n <div :class=\"inDrawer ? 'dou-pivot-fields is-in-drawer' : 'dou-pivot-fields__body'\">\n <section class=\"dou-pivot-fields__list-part\" :aria-label=\"messages.fields.list\">\n <DouInput\n v-model=\"query\"\n size=\"sm\"\n type=\"search\"\n clearable\n :placeholder=\"messages.fields.search\"\n :aria-label=\"messages.fields.search\"\n >\n <template #prefix><SearchIcon aria-hidden=\"true\" /></template>\n </DouInput>\n <DouSortable\n v-model=\"listItems\"\n class=\"dou-pivot-fields__list\"\n :group=\"group\"\n :animation=\"false\"\n item-key=\"key\"\n :item-label=\"(item) => itemLabel(item)\"\n >\n <template #default=\"{ item }\">\n <div class=\"dou-pivot-fields__field\">\n <DouCheckbox\n size=\"sm\"\n :model-value=\"used.has(item.field)\"\n :aria-label=\"itemLabel(item)\"\n @update:model-value=\"toggleField(item.field, !!$event)\"\n />\n <component\n :is=\"TYPE_ICON[field(item.field).type]\"\n class=\"dou-pivot-fields__type\"\n aria-hidden=\"true\"\n />\n <span class=\"dou-pivot-fields__name\">{{ itemLabel(item) }}</span>\n </div>\n </template>\n <template #empty>\n <p class=\"dou-pivot-fields__none\">{{ messages.fields.noFields }}</p>\n </template>\n </DouSortable>\n </section>\n\n <div class=\"dou-pivot-fields__areas\">\n <section\n v-for=\"area in AREAS\"\n :key=\"area\"\n class=\"dou-pivot-fields__area\"\n :class=\"`is-${area}`\"\n :aria-label=\"areaTitle(area)\"\n >\n <h3 class=\"dou-pivot-fields__area-title\">\n <component :is=\"AREA_ICON[area]\" aria-hidden=\"true\" />\n {{ areaTitle(area) }}\n </h3>\n <DouSortable\n v-model=\"models[area].value\"\n class=\"dou-pivot-fields__chips\"\n :group=\"group\"\n item-key=\"key\"\n :item-label=\"(item) => chipText(item)\"\n >\n <template #default=\"{ item }\">\n <div class=\"dou-pivot-fields__chip\" :class=\"{ 'is-filtered': filtered(item) }\">\n <span class=\"dou-pivot-fields__chip-text\" :title=\"chipText(item)\">\n <span class=\"dou-pivot-fields__chip-name\">{{ chipName(item) }}</span>\n <span v-if=\"chipGroup(item)\" class=\"dou-pivot-fields__chip-group\">{{\n chipGroup(item)\n }}</span>\n </span>\n <DouPopover\n v-if=\"canFilter(item)\"\n :open=\"filterOpen === item.key\"\n placement=\"bottom-start\"\n :width=\"260\"\n @update:open=\"setFilterOpen(item.key, $event)\"\n >\n <button\n type=\"button\"\n class=\"dou-pivot-fields__chip-button\"\n :class=\"{ 'is-on': filtered(item) }\"\n :aria-label=\"\n filtered(item)\n ? `${messages.fields.filtered},${format(messages.filter.title, { field: itemLabel(item) })}`\n : format(messages.filter.title, { field: itemLabel(item) })\n \"\n >\n <FilterIcon aria-hidden=\"true\" />\n </button>\n <template #content>\n <!-- a fresh list each time it opens, picked as the filter is now -->\n <FilterList\n :key=\"filterOpen === item.key ? 'open' : 'closed'\"\n :source=\"source as never\"\n :field=\"item.field\"\n :by=\"filterBy(item)\"\n :filter=\"filterOf(item.field)\"\n :messages=\"messages\"\n @apply=\"applyFilter(item, $event)\"\n @cancel=\"filterOpen = null\"\n />\n </template>\n </DouPopover>\n <DouDropdown placement=\"bottom-end\">\n <button\n type=\"button\"\n class=\"dou-pivot-fields__chip-button\"\n :aria-label=\"format(messages.fields.menu, { field: chipText(item) })\"\n >\n <ChevronDownIcon aria-hidden=\"true\" />\n </button>\n <template #menu>\n <template v-if=\"item.kind === 'dimension'\">\n <DouDropdownSub :title=\"messages.fields.sort\">\n <DouDropdownRadioGroup\n :model-value=\"sortKey(axisOf(item), item.field)\"\n @update:model-value=\"onSort(axisOf(item), item.field, $event!)\"\n >\n <DouDropdownItem value=\"asc\">{{ messages.fields.asc }}</DouDropdownItem>\n <DouDropdownItem value=\"desc\">{{\n messages.fields.desc\n }}</DouDropdownItem>\n <template v-if=\"axisOf(item) === 'rows'\">\n <template v-for=\"(value, index) in areas.values\" :key=\"value.key\">\n <DouDropdownItem\n :value=\"`v:${index}:desc`\"\n :divided=\"index === 0\"\n >{{\n format(messages.fields.byValueDesc, { value: chipText(value) })\n }}</DouDropdownItem\n >\n <DouDropdownItem :value=\"`v:${index}:asc`\">{{\n format(messages.fields.byValueAsc, { value: chipText(value) })\n }}</DouDropdownItem>\n </template>\n </template>\n </DouDropdownRadioGroup>\n </DouDropdownSub>\n <DouDropdownSub\n v-if=\"groupingsFor(item.field).length\"\n :title=\"messages.fields.groupBy\"\n >\n <DouDropdownRadioGroup\n :model-value=\"groupKey(dimensionOf(axisOf(item), item.field)?.by)\"\n @update:model-value=\"onGroup(axisOf(item), item.field, $event!)\"\n >\n <DouDropdownItem\n v-for=\"option in groupingsFor(item.field)\"\n :key=\"option.key\"\n :value=\"option.key\"\n >{{ option.text }}</DouDropdownItem\n >\n </DouDropdownRadioGroup>\n </DouDropdownSub>\n <DouDropdownSub :title=\"messages.fields.top\">\n <DouDropdownRadioGroup\n :model-value=\"topKey(item.field)\"\n @update:model-value=\"onTop(item, $event!)\"\n >\n <DouDropdownItem\n v-for=\"option in topOptions(item.field)\"\n :key=\"option.key\"\n :value=\"option.key\"\n :divided=\"option.key === 'b5'\"\n >{{ option.text }}</DouDropdownItem\n >\n </DouDropdownRadioGroup>\n <DouDropdownItem divided @click=\"openTop(item)\">{{\n messages.fields.customTop\n }}</DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem\n :checked=\"dimensionOf(axisOf(item), item.field)?.subtotal !== false\"\n @update:checked=\"onSubtotal(axisOf(item), item.field, $event)\"\n >{{ messages.fields.subtotal }}</DouDropdownItem\n >\n </template>\n <template v-if=\"item.kind === 'value'\">\n <DouDropdownItem v-if=\"isFormula(item)\" @click=\"openFormula(item.index)\">{{\n messages.fields.editFormula\n }}</DouDropdownItem>\n <DouDropdownSub v-else :title=\"messages.fields.aggregate\">\n <DouDropdownRadioGroup\n :model-value=\"currentAggregate(item.index)\"\n @update:model-value=\"onAggregate(item.index, $event!)\"\n >\n <DouDropdownItem\n v-for=\"name in aggregatesFor(item.field)\"\n :key=\"name\"\n :value=\"name\"\n >{{ aggregateText(name) }}</DouDropdownItem\n >\n </DouDropdownRadioGroup>\n </DouDropdownSub>\n <DouDropdownSub :title=\"messages.fields.showAs\">\n <DouDropdownRadioGroup\n :model-value=\"showKey(item.index)\"\n @update:model-value=\"onShow(item.index, $event!)\"\n >\n <DouDropdownItem value=\"\">{{\n messages.fields.showPlain\n }}</DouDropdownItem>\n <DouDropdownItem\n v-for=\"(show, i) in SHOWS\"\n :key=\"show\"\n :value=\"show\"\n :divided=\"i === 0 || show === 'difference'\"\n >{{ messages.shows[show] }}</DouDropdownItem\n >\n </DouDropdownRadioGroup>\n </DouDropdownSub>\n <DouDropdownSub :title=\"messages.fields.mark\">\n <DouDropdownRadioGroup\n :model-value=\"markKey(item.index)\"\n @update:model-value=\"onMark(item.index, $event!)\"\n >\n <DouDropdownItem value=\"\">{{ messages.fields.noMark }}</DouDropdownItem>\n <DouDropdownItem value=\"bar\">{{ messages.fields.bar }}</DouDropdownItem>\n <DouDropdownItem value=\"scale\">{{\n messages.fields.scale\n }}</DouDropdownItem>\n </DouDropdownRadioGroup>\n </DouDropdownSub>\n <DouDropdownItem\n v-if=\"(config.values?.length ?? 0) > 1\"\n :checked=\"config.valuesOn === 'rows'\"\n @update:checked=\"\n config = { ...config, valuesOn: $event ? 'rows' : 'columns' }\n \"\n >{{ messages.fields.valuesOnRows }}</DouDropdownItem\n >\n </template>\n <DouDropdownItem v-if=\"canFilter(item)\" @click=\"openFilter(item)\">{{\n messages.fields.filter\n }}</DouDropdownItem>\n <DouDropdownItem\n divided\n :disabled=\"placeOf(item).first\"\n @click=\"shift(item, -1)\"\n >{{ messages.fields.moveUp }}</DouDropdownItem\n >\n <DouDropdownItem :disabled=\"placeOf(item).last\" @click=\"shift(item, 1)\">{{\n messages.fields.moveDown\n }}</DouDropdownItem>\n <DouDropdownSub :title=\"messages.fields.moveTo\">\n <DouDropdownItem\n v-for=\"to in otherAreas(item)\"\n :key=\"to\"\n @click=\"moveTo(item, to)\"\n >{{ areaTitle(to) }}</DouDropdownItem\n >\n </DouDropdownSub>\n <DouDropdownItem tone=\"danger\" @click=\"moveTo(item, null)\">{{\n messages.fields.remove\n }}</DouDropdownItem>\n </template>\n </DouDropdown>\n </div>\n </template>\n <template #empty>\n <p class=\"dou-pivot-fields__drop\">{{ messages.fields.dropHere }}</p>\n </template>\n </DouSortable>\n <DouButton\n v-if=\"area === 'values'\"\n class=\"dou-pivot-fields__add\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"openFormula(-1)\"\n >\n <template #leading><PlusIcon aria-hidden=\"true\" /></template>\n {{ messages.fields.addFormula }}\n </DouButton>\n </section>\n </div>\n </div>\n </component>\n <FormulaDialog\n v-model:open=\"formulaOpen\"\n :source=\"source as PivotSource<unknown>\"\n :messages=\"messages\"\n :initial=\"formulaInitial\"\n @apply=\"applyFormula\"\n />\n <TopDialog\n v-model:open=\"topOpen\"\n :messages=\"messages\"\n :field=\"topItem ? itemLabel(topItem) : ''\"\n :values=\"areas.values.map((v) => chipText(v))\"\n :filter=\"topItem ? filterOf(topItem.field) : undefined\"\n @apply=\"topItem && setRank(topItem, $event)\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import filter_list_vue_vue_type_script_setup_true_lang_default from "./filter-list.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/fields/filter-list.vue
|
|
3
|
+
var filter_list_default = filter_list_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { filter_list_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=filter-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-list.js","names":["_sfc_main"],"sources":["../../src/fields/filter-list.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, DouCheckbox, DouInput, DouVirtualList, useLocale } from 'dou-ui'\nimport { SearchIcon } from '@dou-ui/icons'\nimport { computed, ref, shallowRef } from 'vue'\nimport type { PivotSource } from '../engine'\nimport type { PivotGroupBy } from '../engine/group'\nimport type { PivotFilter } from '../engine/types'\nimport { labelFormatter } from '../core/format'\nimport { format, type PivotMessages } from '../locale'\n\nconst props = defineProps<{\n source: PivotSource<unknown>\n field: string\n by?: PivotGroupBy\n filter?: PivotFilter\n messages: PivotMessages\n}>()\nconst emit = defineEmits<{ apply: [filter: PivotFilter | null]; cancel: [] }>()\n\nconst ROW = 32\nconst { locale } = useLocale()\n\n/** Each group of the field, in its natural order, with how many records it has. */\nconst groups = computed(() => {\n const column = props.source.dimension(props.field, props.by)\n const m = props.messages\n const write = labelFormatter(\n props.source.field(props.field),\n locale.value.name,\n {\n empty: m.empty,\n yes: m.yes,\n no: m.no,\n year: m.yearLabel,\n quarter: m.quarterLabel,\n week: m.weekLabel,\n range: m.rangeLabel,\n },\n props.by,\n )\n const counts = new Uint32Array(column.labels.length)\n for (let i = 0; i < column.codes.length; i++) counts[column.codes[i]!]!++\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\n const order = Array.from(column.labels.keys()).sort((a, b) => column.rank[a]! - column.rank[b]!)\n return order.map((code) => ({\n code,\n value: column.labels[code],\n text: write(column.labels[code]),\n count: counts[code]!,\n }))\n})\n\n/** Picked groups, by group number; starts from the filter as it is. */\nconst picked = shallowRef(initial())\nfunction initial() {\n const column = props.source.dimension(props.field, props.by)\n const keep = new Uint8Array(column.labels.length)\n const f = props.filter\n if (f?.include) for (const v of f.include) mark(keep, column.find(v), 1)\n else {\n keep.fill(1)\n for (const v of f?.exclude ?? []) mark(keep, column.find(v), 0)\n }\n return keep\n}\nfunction mark(keep: Uint8Array, code: number, to: 0 | 1) {\n if (code >= 0) keep[code] = to\n}\n\nconst query = ref('')\nconst shown = computed(() => {\n const q = query.value.trim().toLocaleLowerCase()\n return q ? groups.value.filter((g) => g.text.toLocaleLowerCase().includes(q)) : groups.value\n})\n\nconst pickedCount = computed(() => picked.value.reduce((n, v) => n + v, 0))\nconst shownPicked = computed(() => shown.value.filter((g) => picked.value[g.code]).length)\nconst allShown = computed(() => shown.value.length > 0 && shownPicked.value === shown.value.length)\n\nfunction toggle(code: number, on: boolean) {\n const next = picked.value.slice()\n next[code] = on ? 1 : 0\n picked.value = next\n}\nfunction toggleShown(on: boolean) {\n const next = picked.value.slice()\n for (const g of shown.value) next[g.code] = on ? 1 : 0\n picked.value = next\n}\n\nfunction apply() {\n const total = groups.value.length\n const count = pickedCount.value\n if (count === total) return emit('apply', null)\n const keep = picked.value\n const values = (on: number) => groups.value.filter((g) => keep[g.code] === on).map((g) => g.value)\n // the shorter list; leaving some out keeps groups that show up later\n const filter: PivotFilter =\n total - count <= count ? { exclude: values(0) } : { include: values(1) }\n if (props.by !== undefined) filter.by = props.by\n emit('apply', filter)\n}\n\nconst fieldLabel = computed(() => props.source.field(props.field).label)\n</script>\n\n<template>\n <div\n class=\"dou-pivot-filter\"\n role=\"group\"\n :aria-label=\"format(messages.filter.title, { field: fieldLabel })\"\n >\n <DouInput\n v-model=\"query\"\n class=\"dou-pivot-filter__search\"\n size=\"sm\"\n type=\"search\"\n clearable\n :placeholder=\"messages.filter.search\"\n :aria-label=\"messages.filter.search\"\n >\n <template #prefix><SearchIcon aria-hidden=\"true\" /></template>\n </DouInput>\n <div class=\"dou-pivot-filter__all\">\n <DouCheckbox\n :model-value=\"allShown\"\n :indeterminate=\"shownPicked > 0 && !allShown\"\n :disabled=\"!shown.length\"\n size=\"sm\"\n @update:model-value=\"toggleShown(!!$event)\"\n >\n {{ messages.filter.all }}\n </DouCheckbox>\n </div>\n <DouVirtualList\n v-if=\"shown.length\"\n class=\"dou-pivot-filter__list\"\n :items=\"shown\"\n :item-size=\"ROW\"\n item-key=\"code\"\n :height=\"Math.min(shown.length * ROW, ROW * 8)\"\n >\n <template #default=\"{ item }\">\n <div class=\"dou-pivot-filter__item\">\n <DouCheckbox\n :model-value=\"!!picked[item.code]\"\n size=\"sm\"\n @update:model-value=\"toggle(item.code, !!$event)\"\n >\n <span class=\"dou-pivot-filter__text\">{{ item.text }}</span>\n </DouCheckbox>\n <span class=\"dou-pivot-filter__count\">{{ item.count.toLocaleString(locale.name) }}</span>\n </div>\n </template>\n </DouVirtualList>\n <p v-else class=\"dou-pivot-filter__none\">{{ messages.filter.noMatch }}</p>\n <div class=\"dou-pivot-filter__foot\">\n <span class=\"dou-pivot-filter__picked\">{{\n format(messages.filter.count, { picked: pickedCount, total: groups.length })\n }}</span>\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"emit('cancel')\">{{\n messages.filter.cancel\n }}</DouButton>\n <DouButton size=\"sm\" tone=\"primary\" :disabled=\"pickedCount === 0\" @click=\"apply\">{{\n messages.filter.apply\n }}</DouButton>\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { labelFormatter } from "../core/format.js";
|
|
2
|
+
import { format } from "../locale.js";
|
|
3
|
+
import { DouButton, DouCheckbox, DouInput, DouVirtualList, useLocale } from "dou-ui";
|
|
4
|
+
import { computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, shallowRef, toDisplayString, unref, withCtx } from "vue";
|
|
5
|
+
import { SearchIcon } from "@dou-ui/icons";
|
|
6
|
+
// src/fields/filter-list.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
+
var _hoisted_1 = ["aria-label"];
|
|
8
|
+
var _hoisted_2 = { class: "dou-pivot-filter__all" };
|
|
9
|
+
var _hoisted_3 = { class: "dou-pivot-filter__item" };
|
|
10
|
+
var _hoisted_4 = { class: "dou-pivot-filter__text" };
|
|
11
|
+
var _hoisted_5 = { class: "dou-pivot-filter__count" };
|
|
12
|
+
var _hoisted_6 = {
|
|
13
|
+
key: 1,
|
|
14
|
+
class: "dou-pivot-filter__none"
|
|
15
|
+
};
|
|
16
|
+
var _hoisted_7 = { class: "dou-pivot-filter__foot" };
|
|
17
|
+
var _hoisted_8 = { class: "dou-pivot-filter__picked" };
|
|
18
|
+
var ROW = 32;
|
|
19
|
+
var filter_list_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
20
|
+
__name: "filter-list",
|
|
21
|
+
props: {
|
|
22
|
+
source: {},
|
|
23
|
+
field: {},
|
|
24
|
+
by: {},
|
|
25
|
+
filter: {},
|
|
26
|
+
messages: {}
|
|
27
|
+
},
|
|
28
|
+
emits: ["apply", "cancel"],
|
|
29
|
+
setup(__props, { emit: __emit }) {
|
|
30
|
+
const props = __props;
|
|
31
|
+
const emit = __emit;
|
|
32
|
+
const { locale } = useLocale();
|
|
33
|
+
/** Each group of the field, in its natural order, with how many records it has. */
|
|
34
|
+
const groups = computed(() => {
|
|
35
|
+
const column = props.source.dimension(props.field, props.by);
|
|
36
|
+
const m = props.messages;
|
|
37
|
+
const write = labelFormatter(props.source.field(props.field), locale.value.name, {
|
|
38
|
+
empty: m.empty,
|
|
39
|
+
yes: m.yes,
|
|
40
|
+
no: m.no,
|
|
41
|
+
year: m.yearLabel,
|
|
42
|
+
quarter: m.quarterLabel,
|
|
43
|
+
week: m.weekLabel,
|
|
44
|
+
range: m.rangeLabel
|
|
45
|
+
}, props.by);
|
|
46
|
+
const counts = new Uint32Array(column.labels.length);
|
|
47
|
+
for (let i = 0; i < column.codes.length; i++) counts[column.codes[i]]++;
|
|
48
|
+
return Array.from(column.labels.keys()).sort((a, b) => column.rank[a] - column.rank[b]).map((code) => ({
|
|
49
|
+
code,
|
|
50
|
+
value: column.labels[code],
|
|
51
|
+
text: write(column.labels[code]),
|
|
52
|
+
count: counts[code]
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
/** Picked groups, by group number; starts from the filter as it is. */
|
|
56
|
+
const picked = shallowRef(initial());
|
|
57
|
+
function initial() {
|
|
58
|
+
const column = props.source.dimension(props.field, props.by);
|
|
59
|
+
const keep = new Uint8Array(column.labels.length);
|
|
60
|
+
const f = props.filter;
|
|
61
|
+
if (f?.include) for (const v of f.include) mark(keep, column.find(v), 1);
|
|
62
|
+
else {
|
|
63
|
+
keep.fill(1);
|
|
64
|
+
for (const v of f?.exclude ?? []) mark(keep, column.find(v), 0);
|
|
65
|
+
}
|
|
66
|
+
return keep;
|
|
67
|
+
}
|
|
68
|
+
function mark(keep, code, to) {
|
|
69
|
+
if (code >= 0) keep[code] = to;
|
|
70
|
+
}
|
|
71
|
+
const query = ref("");
|
|
72
|
+
const shown = computed(() => {
|
|
73
|
+
const q = query.value.trim().toLocaleLowerCase();
|
|
74
|
+
return q ? groups.value.filter((g) => g.text.toLocaleLowerCase().includes(q)) : groups.value;
|
|
75
|
+
});
|
|
76
|
+
const pickedCount = computed(() => picked.value.reduce((n, v) => n + v, 0));
|
|
77
|
+
const shownPicked = computed(() => shown.value.filter((g) => picked.value[g.code]).length);
|
|
78
|
+
const allShown = computed(() => shown.value.length > 0 && shownPicked.value === shown.value.length);
|
|
79
|
+
function toggle(code, on) {
|
|
80
|
+
const next = picked.value.slice();
|
|
81
|
+
next[code] = on ? 1 : 0;
|
|
82
|
+
picked.value = next;
|
|
83
|
+
}
|
|
84
|
+
function toggleShown(on) {
|
|
85
|
+
const next = picked.value.slice();
|
|
86
|
+
for (const g of shown.value) next[g.code] = on ? 1 : 0;
|
|
87
|
+
picked.value = next;
|
|
88
|
+
}
|
|
89
|
+
function apply() {
|
|
90
|
+
const total = groups.value.length;
|
|
91
|
+
const count = pickedCount.value;
|
|
92
|
+
if (count === total) return emit("apply", null);
|
|
93
|
+
const keep = picked.value;
|
|
94
|
+
const values = (on) => groups.value.filter((g) => keep[g.code] === on).map((g) => g.value);
|
|
95
|
+
const filter = total - count <= count ? { exclude: values(0) } : { include: values(1) };
|
|
96
|
+
if (props.by !== void 0) filter.by = props.by;
|
|
97
|
+
emit("apply", filter);
|
|
98
|
+
}
|
|
99
|
+
const fieldLabel = computed(() => props.source.field(props.field).label);
|
|
100
|
+
return (_ctx, _cache) => {
|
|
101
|
+
return openBlock(), createElementBlock("div", {
|
|
102
|
+
class: "dou-pivot-filter",
|
|
103
|
+
role: "group",
|
|
104
|
+
"aria-label": unref(format)(__props.messages.filter.title, { field: fieldLabel.value })
|
|
105
|
+
}, [
|
|
106
|
+
createVNode(unref(DouInput), {
|
|
107
|
+
modelValue: query.value,
|
|
108
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
|
|
109
|
+
class: "dou-pivot-filter__search",
|
|
110
|
+
size: "sm",
|
|
111
|
+
type: "search",
|
|
112
|
+
clearable: "",
|
|
113
|
+
placeholder: __props.messages.filter.search,
|
|
114
|
+
"aria-label": __props.messages.filter.search
|
|
115
|
+
}, {
|
|
116
|
+
prefix: withCtx(() => [createVNode(unref(SearchIcon), { "aria-hidden": "true" })]),
|
|
117
|
+
_: 1
|
|
118
|
+
}, 8, [
|
|
119
|
+
"modelValue",
|
|
120
|
+
"placeholder",
|
|
121
|
+
"aria-label"
|
|
122
|
+
]),
|
|
123
|
+
createElementVNode("div", _hoisted_2, [createVNode(unref(DouCheckbox), {
|
|
124
|
+
"model-value": allShown.value,
|
|
125
|
+
indeterminate: shownPicked.value > 0 && !allShown.value,
|
|
126
|
+
disabled: !shown.value.length,
|
|
127
|
+
size: "sm",
|
|
128
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => toggleShown(!!$event))
|
|
129
|
+
}, {
|
|
130
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.filter.all), 1)]),
|
|
131
|
+
_: 1
|
|
132
|
+
}, 8, [
|
|
133
|
+
"model-value",
|
|
134
|
+
"indeterminate",
|
|
135
|
+
"disabled"
|
|
136
|
+
])]),
|
|
137
|
+
shown.value.length ? (openBlock(), createBlock(unref(DouVirtualList), {
|
|
138
|
+
key: 0,
|
|
139
|
+
class: "dou-pivot-filter__list",
|
|
140
|
+
items: shown.value,
|
|
141
|
+
"item-size": ROW,
|
|
142
|
+
"item-key": "code",
|
|
143
|
+
height: Math.min(shown.value.length * ROW, 256)
|
|
144
|
+
}, {
|
|
145
|
+
default: withCtx(({ item }) => [createElementVNode("div", _hoisted_3, [createVNode(unref(DouCheckbox), {
|
|
146
|
+
"model-value": !!picked.value[item.code],
|
|
147
|
+
size: "sm",
|
|
148
|
+
"onUpdate:modelValue": ($event) => toggle(item.code, !!$event)
|
|
149
|
+
}, {
|
|
150
|
+
default: withCtx(() => [createElementVNode("span", _hoisted_4, toDisplayString(item.text), 1)]),
|
|
151
|
+
_: 2
|
|
152
|
+
}, 1032, ["model-value", "onUpdate:modelValue"]), createElementVNode("span", _hoisted_5, toDisplayString(item.count.toLocaleString(unref(locale).name)), 1)])]),
|
|
153
|
+
_: 1
|
|
154
|
+
}, 8, ["items", "height"])) : (openBlock(), createElementBlock("p", _hoisted_6, toDisplayString(__props.messages.filter.noMatch), 1)),
|
|
155
|
+
createElementVNode("div", _hoisted_7, [
|
|
156
|
+
createElementVNode("span", _hoisted_8, toDisplayString(unref(format)(__props.messages.filter.count, {
|
|
157
|
+
picked: pickedCount.value,
|
|
158
|
+
total: groups.value.length
|
|
159
|
+
})), 1),
|
|
160
|
+
createVNode(unref(DouButton), {
|
|
161
|
+
size: "sm",
|
|
162
|
+
variant: "ghost",
|
|
163
|
+
onClick: _cache[2] || (_cache[2] = ($event) => emit("cancel"))
|
|
164
|
+
}, {
|
|
165
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.filter.cancel), 1)]),
|
|
166
|
+
_: 1
|
|
167
|
+
}),
|
|
168
|
+
createVNode(unref(DouButton), {
|
|
169
|
+
size: "sm",
|
|
170
|
+
tone: "primary",
|
|
171
|
+
disabled: pickedCount.value === 0,
|
|
172
|
+
onClick: apply
|
|
173
|
+
}, {
|
|
174
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.filter.apply), 1)]),
|
|
175
|
+
_: 1
|
|
176
|
+
}, 8, ["disabled"])
|
|
177
|
+
])
|
|
178
|
+
], 8, _hoisted_1);
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
export { filter_list_vue_vue_type_script_setup_true_lang_default as default };
|
|
183
|
+
|
|
184
|
+
//# sourceMappingURL=filter-list.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-list.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_unref","_createVNode","_withCtx","_createElementVNode","_createTextVNode","_toDisplayString","_createBlock"],"sources":["../../src/fields/filter-list.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, DouCheckbox, DouInput, DouVirtualList, useLocale } from 'dou-ui'\nimport { SearchIcon } from '@dou-ui/icons'\nimport { computed, ref, shallowRef } from 'vue'\nimport type { PivotSource } from '../engine'\nimport type { PivotGroupBy } from '../engine/group'\nimport type { PivotFilter } from '../engine/types'\nimport { labelFormatter } from '../core/format'\nimport { format, type PivotMessages } from '../locale'\n\nconst props = defineProps<{\n source: PivotSource<unknown>\n field: string\n by?: PivotGroupBy\n filter?: PivotFilter\n messages: PivotMessages\n}>()\nconst emit = defineEmits<{ apply: [filter: PivotFilter | null]; cancel: [] }>()\n\nconst ROW = 32\nconst { locale } = useLocale()\n\n/** Each group of the field, in its natural order, with how many records it has. */\nconst groups = computed(() => {\n const column = props.source.dimension(props.field, props.by)\n const m = props.messages\n const write = labelFormatter(\n props.source.field(props.field),\n locale.value.name,\n {\n empty: m.empty,\n yes: m.yes,\n no: m.no,\n year: m.yearLabel,\n quarter: m.quarterLabel,\n week: m.weekLabel,\n range: m.rangeLabel,\n },\n props.by,\n )\n const counts = new Uint32Array(column.labels.length)\n for (let i = 0; i < column.codes.length; i++) counts[column.codes[i]!]!++\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\n const order = Array.from(column.labels.keys()).sort((a, b) => column.rank[a]! - column.rank[b]!)\n return order.map((code) => ({\n code,\n value: column.labels[code],\n text: write(column.labels[code]),\n count: counts[code]!,\n }))\n})\n\n/** Picked groups, by group number; starts from the filter as it is. */\nconst picked = shallowRef(initial())\nfunction initial() {\n const column = props.source.dimension(props.field, props.by)\n const keep = new Uint8Array(column.labels.length)\n const f = props.filter\n if (f?.include) for (const v of f.include) mark(keep, column.find(v), 1)\n else {\n keep.fill(1)\n for (const v of f?.exclude ?? []) mark(keep, column.find(v), 0)\n }\n return keep\n}\nfunction mark(keep: Uint8Array, code: number, to: 0 | 1) {\n if (code >= 0) keep[code] = to\n}\n\nconst query = ref('')\nconst shown = computed(() => {\n const q = query.value.trim().toLocaleLowerCase()\n return q ? groups.value.filter((g) => g.text.toLocaleLowerCase().includes(q)) : groups.value\n})\n\nconst pickedCount = computed(() => picked.value.reduce((n, v) => n + v, 0))\nconst shownPicked = computed(() => shown.value.filter((g) => picked.value[g.code]).length)\nconst allShown = computed(() => shown.value.length > 0 && shownPicked.value === shown.value.length)\n\nfunction toggle(code: number, on: boolean) {\n const next = picked.value.slice()\n next[code] = on ? 1 : 0\n picked.value = next\n}\nfunction toggleShown(on: boolean) {\n const next = picked.value.slice()\n for (const g of shown.value) next[g.code] = on ? 1 : 0\n picked.value = next\n}\n\nfunction apply() {\n const total = groups.value.length\n const count = pickedCount.value\n if (count === total) return emit('apply', null)\n const keep = picked.value\n const values = (on: number) => groups.value.filter((g) => keep[g.code] === on).map((g) => g.value)\n // the shorter list; leaving some out keeps groups that show up later\n const filter: PivotFilter =\n total - count <= count ? { exclude: values(0) } : { include: values(1) }\n if (props.by !== undefined) filter.by = props.by\n emit('apply', filter)\n}\n\nconst fieldLabel = computed(() => props.source.field(props.field).label)\n</script>\n\n<template>\n <div\n class=\"dou-pivot-filter\"\n role=\"group\"\n :aria-label=\"format(messages.filter.title, { field: fieldLabel })\"\n >\n <DouInput\n v-model=\"query\"\n class=\"dou-pivot-filter__search\"\n size=\"sm\"\n type=\"search\"\n clearable\n :placeholder=\"messages.filter.search\"\n :aria-label=\"messages.filter.search\"\n >\n <template #prefix><SearchIcon aria-hidden=\"true\" /></template>\n </DouInput>\n <div class=\"dou-pivot-filter__all\">\n <DouCheckbox\n :model-value=\"allShown\"\n :indeterminate=\"shownPicked > 0 && !allShown\"\n :disabled=\"!shown.length\"\n size=\"sm\"\n @update:model-value=\"toggleShown(!!$event)\"\n >\n {{ messages.filter.all }}\n </DouCheckbox>\n </div>\n <DouVirtualList\n v-if=\"shown.length\"\n class=\"dou-pivot-filter__list\"\n :items=\"shown\"\n :item-size=\"ROW\"\n item-key=\"code\"\n :height=\"Math.min(shown.length * ROW, ROW * 8)\"\n >\n <template #default=\"{ item }\">\n <div class=\"dou-pivot-filter__item\">\n <DouCheckbox\n :model-value=\"!!picked[item.code]\"\n size=\"sm\"\n @update:model-value=\"toggle(item.code, !!$event)\"\n >\n <span class=\"dou-pivot-filter__text\">{{ item.text }}</span>\n </DouCheckbox>\n <span class=\"dou-pivot-filter__count\">{{ item.count.toLocaleString(locale.name) }}</span>\n </div>\n </template>\n </DouVirtualList>\n <p v-else class=\"dou-pivot-filter__none\">{{ messages.filter.noMatch }}</p>\n <div class=\"dou-pivot-filter__foot\">\n <span class=\"dou-pivot-filter__picked\">{{\n format(messages.filter.count, { picked: pickedCount, total: groups.length })\n }}</span>\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"emit('cancel')\">{{\n messages.filter.cancel\n }}</DouButton>\n <DouButton size=\"sm\" tone=\"primary\" :disabled=\"pickedCount === 0\" @click=\"apply\">{{\n messages.filter.apply\n }}</DouButton>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import formula_dialog_vue_vue_type_script_setup_true_lang_default from "./formula-dialog.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/fields/formula-dialog.vue
|
|
3
|
+
var formula_dialog_default = formula_dialog_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { formula_dialog_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=formula-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formula-dialog.js","names":["_sfc_main"],"sources":["../../src/fields/formula-dialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, DouDialog, DouForm, DouFormItem, DouInput, DouTextarea } from 'dou-ui'\nimport { computed, nextTick, ref, watch } from 'vue'\nimport { checkPivotFormula, PivotFormulaError, type PivotSource } from '../engine'\nimport type { PivotMessages } from '../locale'\nimport { format } from '../locale'\n\nconst props = defineProps<{\n source: PivotSource<unknown>\n messages: PivotMessages\n /** The value being changed, or null for a new one. */\n initial: { formula: string; label?: string } | null\n}>()\nconst open = defineModel<boolean>('open', { required: true })\nconst emit = defineEmits<{ apply: [value: { formula: string; label?: string }] }>()\n\nconst name = ref('')\nconst text = ref('')\n/** Errors show once the formula has been edited, or on applying. */\nconst touched = ref(false)\nconst box = ref<InstanceType<typeof DouTextarea> | null>(null)\n\nwatch(open, (now) => {\n if (!now) return\n name.value = props.initial?.label ?? ''\n text.value = props.initial?.formula ?? ''\n touched.value = false\n})\n\nconst error = computed(() => {\n try {\n checkPivotFormula(props.source, text.value)\n return ''\n } catch (e) {\n if (!(e instanceof PivotFormulaError)) return String(e)\n return format(props.messages.formula.errors[e.code], { detail: e.detail })\n }\n})\n\n/** Number fields, to put in the formula by name. */\nconst numbers = computed(() => [...props.source.fields.values()].filter((f) => f.type === 'number'))\nconst SIMPLE = /^[\\p{L}_$][\\p{L}\\p{N}_$.]*$/u\nconst reference = (label: string, fieldName: string) => {\n // the label reads better; a name in brackets when the label is not one word or is taken\n const labels = [...props.source.fields.values()].filter((f) => f.label === label)\n const word = labels.length === 1 ? label : fieldName\n return SIMPLE.test(word) ? word : `[${word}]`\n}\n\nfunction insert(word: string) {\n const el = box.value?.textarea\n const at = el ? el.selectionStart : text.value.length\n const end = el ? el.selectionEnd : at\n const before = text.value.slice(0, at)\n const pad = before && !/[\\s(]$/.test(before) ? ' ' : ''\n text.value = `${before}${pad}${word}${text.value.slice(end)}`\n touched.value = true\n nextTick(() => {\n const caret = at + pad.length + word.length\n el?.focus()\n el?.setSelectionRange(caret, caret)\n })\n}\n\nfunction apply() {\n touched.value = true\n if (error.value) return\n const label = name.value.trim()\n emit('apply', { formula: text.value.trim(), ...(label ? { label } : {}) })\n open.value = false\n}\n</script>\n\n<template>\n <DouDialog v-model:open=\"open\" :title=\"messages.formula.title\" :width=\"440\">\n <DouForm layout=\"vertical\" class=\"dou-pivot-formula\" @submit=\"apply\">\n <DouFormItem :label=\"messages.formula.name\">\n <DouInput v-model=\"name\" :placeholder=\"messages.formula.namePlaceholder\" />\n </DouFormItem>\n <DouFormItem\n :label=\"messages.formula.formula\"\n :error=\"touched ? error : undefined\"\n :help=\"messages.formula.help\"\n >\n <DouTextarea\n ref=\"box\"\n v-model=\"text\"\n class=\"dou-pivot-formula__box\"\n :rows=\"2\"\n autosize\n :invalid=\"touched && !!error\"\n :placeholder=\"messages.formula.placeholder\"\n @update:model-value=\"touched = true\"\n @keydown.enter.exact.prevent=\"apply\"\n />\n </DouFormItem>\n <div v-if=\"numbers.length\" class=\"dou-pivot-formula__fields\">\n <span class=\"dou-pivot-formula__fields-title\">{{ messages.formula.fields }}</span>\n <DouButton\n v-for=\"f in numbers\"\n :key=\"f.name\"\n size=\"sm\"\n variant=\"outline\"\n @click=\"insert(reference(f.label, f.name))\"\n >{{ f.label }}</DouButton\n >\n </div>\n </DouForm>\n <template #footer=\"{ close }\">\n <DouButton variant=\"outline\" @click=\"close\">{{ messages.formula.cancel }}</DouButton>\n <DouButton variant=\"solid\" :disabled=\"touched && !!error\" @click=\"apply\">{{\n messages.formula.apply\n }}</DouButton>\n </template>\n </DouDialog>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { PivotFormulaError } from "../engine/formula.js";
|
|
2
|
+
import { checkPivotFormula } from "../engine/compute.js";
|
|
3
|
+
import { format } from "../locale.js";
|
|
4
|
+
import { DouButton, DouDialog, DouForm, DouFormItem, DouInput, DouTextarea } from "dou-ui";
|
|
5
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeModels, nextTick, openBlock, ref, renderList, toDisplayString, unref, useModel, watch, withCtx, withKeys, withModifiers } from "vue";
|
|
6
|
+
// src/fields/formula-dialog.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
+
var _hoisted_1 = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "dou-pivot-formula__fields"
|
|
10
|
+
};
|
|
11
|
+
var _hoisted_2 = { class: "dou-pivot-formula__fields-title" };
|
|
12
|
+
var formula_dialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
13
|
+
__name: "formula-dialog",
|
|
14
|
+
props: /*@__PURE__*/ mergeModels({
|
|
15
|
+
source: {},
|
|
16
|
+
messages: {},
|
|
17
|
+
initial: {}
|
|
18
|
+
}, {
|
|
19
|
+
"open": {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
required: true
|
|
22
|
+
},
|
|
23
|
+
"openModifiers": {}
|
|
24
|
+
}),
|
|
25
|
+
emits: /*@__PURE__*/ mergeModels(["apply"], ["update:open"]),
|
|
26
|
+
setup(__props, { emit: __emit }) {
|
|
27
|
+
const props = __props;
|
|
28
|
+
const open = useModel(__props, "open");
|
|
29
|
+
const emit = __emit;
|
|
30
|
+
const name = ref("");
|
|
31
|
+
const text = ref("");
|
|
32
|
+
/** Errors show once the formula has been edited, or on applying. */
|
|
33
|
+
const touched = ref(false);
|
|
34
|
+
const box = ref(null);
|
|
35
|
+
watch(open, (now) => {
|
|
36
|
+
if (!now) return;
|
|
37
|
+
name.value = props.initial?.label ?? "";
|
|
38
|
+
text.value = props.initial?.formula ?? "";
|
|
39
|
+
touched.value = false;
|
|
40
|
+
});
|
|
41
|
+
const error = computed(() => {
|
|
42
|
+
try {
|
|
43
|
+
checkPivotFormula(props.source, text.value);
|
|
44
|
+
return "";
|
|
45
|
+
} catch (e) {
|
|
46
|
+
if (!(e instanceof PivotFormulaError)) return String(e);
|
|
47
|
+
return format(props.messages.formula.errors[e.code], { detail: e.detail });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
/** Number fields, to put in the formula by name. */
|
|
51
|
+
const numbers = computed(() => [...props.source.fields.values()].filter((f) => f.type === "number"));
|
|
52
|
+
const SIMPLE = /^[\p{L}_$][\p{L}\p{N}_$.]*$/u;
|
|
53
|
+
const reference = (label, fieldName) => {
|
|
54
|
+
const word = [...props.source.fields.values()].filter((f) => f.label === label).length === 1 ? label : fieldName;
|
|
55
|
+
return SIMPLE.test(word) ? word : `[${word}]`;
|
|
56
|
+
};
|
|
57
|
+
function insert(word) {
|
|
58
|
+
const el = box.value?.textarea;
|
|
59
|
+
const at = el ? el.selectionStart : text.value.length;
|
|
60
|
+
const end = el ? el.selectionEnd : at;
|
|
61
|
+
const before = text.value.slice(0, at);
|
|
62
|
+
const pad = before && !/[\s(]$/.test(before) ? " " : "";
|
|
63
|
+
text.value = `${before}${pad}${word}${text.value.slice(end)}`;
|
|
64
|
+
touched.value = true;
|
|
65
|
+
nextTick(() => {
|
|
66
|
+
const caret = at + pad.length + word.length;
|
|
67
|
+
el?.focus();
|
|
68
|
+
el?.setSelectionRange(caret, caret);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function apply() {
|
|
72
|
+
touched.value = true;
|
|
73
|
+
if (error.value) return;
|
|
74
|
+
const label = name.value.trim();
|
|
75
|
+
emit("apply", {
|
|
76
|
+
formula: text.value.trim(),
|
|
77
|
+
...label ? { label } : {}
|
|
78
|
+
});
|
|
79
|
+
open.value = false;
|
|
80
|
+
}
|
|
81
|
+
return (_ctx, _cache) => {
|
|
82
|
+
return openBlock(), createBlock(unref(DouDialog), {
|
|
83
|
+
open: open.value,
|
|
84
|
+
"onUpdate:open": _cache[3] || (_cache[3] = ($event) => open.value = $event),
|
|
85
|
+
title: __props.messages.formula.title,
|
|
86
|
+
width: 440
|
|
87
|
+
}, {
|
|
88
|
+
footer: withCtx(({ close }) => [createVNode(unref(DouButton), {
|
|
89
|
+
variant: "outline",
|
|
90
|
+
onClick: close
|
|
91
|
+
}, {
|
|
92
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.formula.cancel), 1)]),
|
|
93
|
+
_: 1
|
|
94
|
+
}, 8, ["onClick"]), createVNode(unref(DouButton), {
|
|
95
|
+
variant: "solid",
|
|
96
|
+
disabled: touched.value && !!error.value,
|
|
97
|
+
onClick: apply
|
|
98
|
+
}, {
|
|
99
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.formula.apply), 1)]),
|
|
100
|
+
_: 1
|
|
101
|
+
}, 8, ["disabled"])]),
|
|
102
|
+
default: withCtx(() => [createVNode(unref(DouForm), {
|
|
103
|
+
layout: "vertical",
|
|
104
|
+
class: "dou-pivot-formula",
|
|
105
|
+
onSubmit: apply
|
|
106
|
+
}, {
|
|
107
|
+
default: withCtx(() => [
|
|
108
|
+
createVNode(unref(DouFormItem), { label: __props.messages.formula.name }, {
|
|
109
|
+
default: withCtx(() => [createVNode(unref(DouInput), {
|
|
110
|
+
modelValue: name.value,
|
|
111
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => name.value = $event),
|
|
112
|
+
placeholder: __props.messages.formula.namePlaceholder
|
|
113
|
+
}, null, 8, ["modelValue", "placeholder"])]),
|
|
114
|
+
_: 1
|
|
115
|
+
}, 8, ["label"]),
|
|
116
|
+
createVNode(unref(DouFormItem), {
|
|
117
|
+
label: __props.messages.formula.formula,
|
|
118
|
+
error: touched.value ? error.value : void 0,
|
|
119
|
+
help: __props.messages.formula.help
|
|
120
|
+
}, {
|
|
121
|
+
default: withCtx(() => [createVNode(unref(DouTextarea), {
|
|
122
|
+
ref_key: "box",
|
|
123
|
+
ref: box,
|
|
124
|
+
modelValue: text.value,
|
|
125
|
+
"onUpdate:modelValue": [_cache[1] || (_cache[1] = ($event) => text.value = $event), _cache[2] || (_cache[2] = ($event) => touched.value = true)],
|
|
126
|
+
class: "dou-pivot-formula__box",
|
|
127
|
+
rows: 2,
|
|
128
|
+
autosize: "",
|
|
129
|
+
invalid: touched.value && !!error.value,
|
|
130
|
+
placeholder: __props.messages.formula.placeholder,
|
|
131
|
+
onKeydown: withKeys(withModifiers(apply, ["exact", "prevent"]), ["enter"])
|
|
132
|
+
}, null, 8, [
|
|
133
|
+
"modelValue",
|
|
134
|
+
"invalid",
|
|
135
|
+
"placeholder",
|
|
136
|
+
"onKeydown"
|
|
137
|
+
])]),
|
|
138
|
+
_: 1
|
|
139
|
+
}, 8, [
|
|
140
|
+
"label",
|
|
141
|
+
"error",
|
|
142
|
+
"help"
|
|
143
|
+
]),
|
|
144
|
+
numbers.value.length ? (openBlock(), createElementBlock("div", _hoisted_1, [createElementVNode("span", _hoisted_2, toDisplayString(__props.messages.formula.fields), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(numbers.value, (f) => {
|
|
145
|
+
return openBlock(), createBlock(unref(DouButton), {
|
|
146
|
+
key: f.name,
|
|
147
|
+
size: "sm",
|
|
148
|
+
variant: "outline",
|
|
149
|
+
onClick: ($event) => insert(reference(f.label, f.name))
|
|
150
|
+
}, {
|
|
151
|
+
default: withCtx(() => [createTextVNode(toDisplayString(f.label), 1)]),
|
|
152
|
+
_: 2
|
|
153
|
+
}, 1032, ["onClick"]);
|
|
154
|
+
}), 128))])) : createCommentVNode("", true)
|
|
155
|
+
]),
|
|
156
|
+
_: 1
|
|
157
|
+
})]),
|
|
158
|
+
_: 1
|
|
159
|
+
}, 8, ["open", "title"]);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
export { formula_dialog_vue_vue_type_script_setup_true_lang_default as default };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=formula-dialog.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formula-dialog.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createVNode","_createTextVNode","_toDisplayString","_withKeys","_withModifiers","_createElementBlock","_createElementVNode","_Fragment","_renderList","_createCommentVNode"],"sources":["../../src/fields/formula-dialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, DouDialog, DouForm, DouFormItem, DouInput, DouTextarea } from 'dou-ui'\nimport { computed, nextTick, ref, watch } from 'vue'\nimport { checkPivotFormula, PivotFormulaError, type PivotSource } from '../engine'\nimport type { PivotMessages } from '../locale'\nimport { format } from '../locale'\n\nconst props = defineProps<{\n source: PivotSource<unknown>\n messages: PivotMessages\n /** The value being changed, or null for a new one. */\n initial: { formula: string; label?: string } | null\n}>()\nconst open = defineModel<boolean>('open', { required: true })\nconst emit = defineEmits<{ apply: [value: { formula: string; label?: string }] }>()\n\nconst name = ref('')\nconst text = ref('')\n/** Errors show once the formula has been edited, or on applying. */\nconst touched = ref(false)\nconst box = ref<InstanceType<typeof DouTextarea> | null>(null)\n\nwatch(open, (now) => {\n if (!now) return\n name.value = props.initial?.label ?? ''\n text.value = props.initial?.formula ?? ''\n touched.value = false\n})\n\nconst error = computed(() => {\n try {\n checkPivotFormula(props.source, text.value)\n return ''\n } catch (e) {\n if (!(e instanceof PivotFormulaError)) return String(e)\n return format(props.messages.formula.errors[e.code], { detail: e.detail })\n }\n})\n\n/** Number fields, to put in the formula by name. */\nconst numbers = computed(() => [...props.source.fields.values()].filter((f) => f.type === 'number'))\nconst SIMPLE = /^[\\p{L}_$][\\p{L}\\p{N}_$.]*$/u\nconst reference = (label: string, fieldName: string) => {\n // the label reads better; a name in brackets when the label is not one word or is taken\n const labels = [...props.source.fields.values()].filter((f) => f.label === label)\n const word = labels.length === 1 ? label : fieldName\n return SIMPLE.test(word) ? word : `[${word}]`\n}\n\nfunction insert(word: string) {\n const el = box.value?.textarea\n const at = el ? el.selectionStart : text.value.length\n const end = el ? el.selectionEnd : at\n const before = text.value.slice(0, at)\n const pad = before && !/[\\s(]$/.test(before) ? ' ' : ''\n text.value = `${before}${pad}${word}${text.value.slice(end)}`\n touched.value = true\n nextTick(() => {\n const caret = at + pad.length + word.length\n el?.focus()\n el?.setSelectionRange(caret, caret)\n })\n}\n\nfunction apply() {\n touched.value = true\n if (error.value) return\n const label = name.value.trim()\n emit('apply', { formula: text.value.trim(), ...(label ? { label } : {}) })\n open.value = false\n}\n</script>\n\n<template>\n <DouDialog v-model:open=\"open\" :title=\"messages.formula.title\" :width=\"440\">\n <DouForm layout=\"vertical\" class=\"dou-pivot-formula\" @submit=\"apply\">\n <DouFormItem :label=\"messages.formula.name\">\n <DouInput v-model=\"name\" :placeholder=\"messages.formula.namePlaceholder\" />\n </DouFormItem>\n <DouFormItem\n :label=\"messages.formula.formula\"\n :error=\"touched ? error : undefined\"\n :help=\"messages.formula.help\"\n >\n <DouTextarea\n ref=\"box\"\n v-model=\"text\"\n class=\"dou-pivot-formula__box\"\n :rows=\"2\"\n autosize\n :invalid=\"touched && !!error\"\n :placeholder=\"messages.formula.placeholder\"\n @update:model-value=\"touched = true\"\n @keydown.enter.exact.prevent=\"apply\"\n />\n </DouFormItem>\n <div v-if=\"numbers.length\" class=\"dou-pivot-formula__fields\">\n <span class=\"dou-pivot-formula__fields-title\">{{ messages.formula.fields }}</span>\n <DouButton\n v-for=\"f in numbers\"\n :key=\"f.name\"\n size=\"sm\"\n variant=\"outline\"\n @click=\"insert(reference(f.label, f.name))\"\n >{{ f.label }}</DouButton\n >\n </div>\n </DouForm>\n <template #footer=\"{ close }\">\n <DouButton variant=\"outline\" @click=\"close\">{{ messages.formula.cancel }}</DouButton>\n <DouButton variant=\"solid\" :disabled=\"touched && !!error\" @click=\"apply\">{{\n messages.formula.apply\n }}</DouButton>\n </template>\n </DouDialog>\n</template>\n"],"mappings":"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"}
|