@shwfed/nuxt 0.11.44 → 0.11.46

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/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
3
  "configKey": "shwfed",
4
- "version": "0.11.44",
4
+ "version": "0.11.46",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -1398,7 +1398,7 @@ function buildDslGuideMarkdown() {
1398
1398
  "- `enableRowSelection`: `row: dyn`\u3001`index: int`\u3001`id: string`\uFF1B\u5FC5\u987B\u8FD4\u56DE `bool`\u3002",
1399
1399
  "- `enableMultiRowSelection`: `row: dyn`\u3001`index: int`\u3001`id: string`\uFF1B\u5FC5\u987B\u8FD4\u56DE `bool`\u3002",
1400
1400
  "- `cellStyles`: `row: dyn`\u3001`index: int`\u3001`id: string`\u3001`selected: bool`\u3001`pinned: dyn`\uFF1B\u5FC5\u987B\u8FD4\u56DE `map`\u3002",
1401
- "- `table.renderer.text.props.copyExpression`: `row: dyn`\u3001`index: int`\u3002",
1401
+ "- `table.renderer.text.props.copyExpression` / `table.renderer.markdown.props.copyExpression`: `row: dyn`\u3001`index: int`\u3002",
1402
1402
  "",
1403
1403
  "### 4. \u53EF\u7528\u7C7B\u578B\u4E0E\u6269\u5C55\u80FD\u529B",
1404
1404
  "- `URL` \u7C7B\u578B\uFF1A\u53EF\u8C03\u7528 `location.searchParams()`\uFF0C\u8FD4\u56DE `URLSearchParams`\u3002",
@@ -1,6 +1,6 @@
1
1
  import { useRoute, useRouter } from "#app";
2
2
  import { useSessionStorage } from "@vueuse/core";
3
- import { computed, toValue, onMounted } from "vue";
3
+ import { computed, toValue, watch } from "vue";
4
4
  export function useNavigationTabs(navigations) {
5
5
  const tabs = useSessionStorage("navigation-tabs", /* @__PURE__ */ new Set(), {
6
6
  writeDefaults: false
@@ -11,11 +11,31 @@ export function useNavigationTabs(navigations) {
11
11
  const clean = (path) => path.replace(/\/$/g, "");
12
12
  const route = useRoute();
13
13
  const router = useRouter();
14
- onMounted(() => {
15
- const path = clean(route.path);
14
+ const matchedRoute = computed(() => {
15
+ const currentPath = clean(route.path);
16
+ for (const group of toValue(navigations)) {
17
+ if ("children" in group) {
18
+ for (const item of group.children) {
19
+ if (clean(item.route) === currentPath) {
20
+ return currentPath;
21
+ }
22
+ }
23
+ } else {
24
+ if (clean(group.route) === currentPath) {
25
+ return currentPath;
26
+ }
27
+ }
28
+ }
29
+ });
30
+ watch(matchedRoute, (path) => {
31
+ if (!path) {
32
+ return;
33
+ }
16
34
  if (!tabs.value.has(path))
17
35
  tabs.value.add(path);
18
36
  active.value = path;
37
+ }, {
38
+ immediate: true
19
39
  });
20
40
  return {
21
41
  tabs,
@@ -284,15 +284,69 @@ const TableRendererMarkdownConfig = defineComponent({
284
284
  emits: ["update:modelValue"],
285
285
  setup(props, { emit, expose }) {
286
286
  const { t } = useTableRendererConfigI18n();
287
+ const copyExpressionEditor = ref(null);
287
288
  const value = () => props.modelValue ?? {};
288
289
  const update = (patch) => {
289
290
  emit("update:modelValue", { ...value(), ...patch });
290
291
  };
291
292
  expose({
292
- clearValidation: () => void 0,
293
- validate: () => true
293
+ clearValidation: () => copyExpressionEditor.value?.clearValidation(),
294
+ validate: () => copyExpressionEditor.value ? copyExpressionEditor.value.validate() : true
294
295
  });
295
296
  return () => /* @__PURE__ */ jsxs("div", { class: "flex flex-col gap-3 text-sm text-zinc-700", children: [
297
+ /* @__PURE__ */ jsxs(
298
+ "label",
299
+ {
300
+ "data-field-key": "rendererCopyable",
301
+ class: "flex items-center justify-between gap-3 py-1",
302
+ children: [
303
+ /* @__PURE__ */ jsxs("div", { class: "flex flex-col gap-1", children: [
304
+ /* @__PURE__ */ jsx("span", { class: "text-sm font-medium text-zinc-800", children: t("copyable") }),
305
+ /* @__PURE__ */ jsx("span", { class: "text-xs text-zinc-500", children: t("copyable-description") })
306
+ ] }),
307
+ /* @__PURE__ */ jsx(
308
+ Switch,
309
+ {
310
+ modelValue: Boolean(value().copyable),
311
+ "onUpdate:modelValue": (...args) => update({ copyable: args[0] === true })
312
+ }
313
+ )
314
+ ]
315
+ }
316
+ ),
317
+ /* @__PURE__ */ jsx(
318
+ ExpressionEditor,
319
+ {
320
+ ref: copyExpressionEditor,
321
+ "data-field-key": "rendererCopyExpression",
322
+ modelValue: value().copyExpression ?? void 0,
323
+ label: t("copy-expression"),
324
+ description: t("copy-expression-description"),
325
+ placeholder: t("copy-expression-placeholder"),
326
+ schema: TEXT_RENDERER_COPY_EXPRESSION_C,
327
+ "onUpdate:modelValue": (nextValue) => update({ copyExpression: nextValue ?? null })
328
+ }
329
+ ),
330
+ /* @__PURE__ */ jsxs("label", { class: "flex flex-col gap-1", children: [
331
+ /* @__PURE__ */ jsx("span", { class: "text-xs font-medium text-zinc-500", children: t("align") }),
332
+ h(NativeSelect, {
333
+ "data-field-key": "rendererAlign",
334
+ "modelValue": value().align ?? "left",
335
+ "class": "w-full",
336
+ "onUpdate:modelValue": (...args) => {
337
+ const nextValue = args[0];
338
+ if (nextValue === "left" || nextValue === "center" || nextValue === "right") {
339
+ update({ align: nextValue });
340
+ }
341
+ }
342
+ }, {
343
+ default: () => [
344
+ h(NativeSelectOption, { value: "left" }, { default: () => t("align-left") }),
345
+ h(NativeSelectOption, { value: "center" }, { default: () => t("align-center") }),
346
+ h(NativeSelectOption, { value: "right" }, { default: () => t("align-right") })
347
+ ]
348
+ })
349
+ ] }),
296
350
  /* @__PURE__ */ jsxs("div", { class: "flex flex-col gap-1", children: [
297
351
  /* @__PURE__ */ jsx("span", { class: "text-xs font-medium text-zinc-500", children: t("markdown") }),
298
352
  /* @__PURE__ */ jsx("span", { class: "text-sm text-zinc-500", children: t("markdown-description", { expression: MARKDOWN_EXPRESSION_EXAMPLE }) })
@@ -331,24 +385,77 @@ const TableRendererMarkdownCell = defineComponent({
331
385
  id: {
332
386
  type: String,
333
387
  required: true
388
+ },
389
+ dslContext: {
390
+ type: Object,
391
+ required: true
392
+ },
393
+ copyable: {
394
+ type: Boolean,
395
+ default: false
396
+ },
397
+ copyExpression: {
398
+ type: String,
399
+ default: null
400
+ },
401
+ align: {
402
+ type: String,
403
+ default: "left"
334
404
  }
335
405
  },
336
406
  setup(props) {
337
407
  const { locale } = useI18n();
338
- const { $md } = useNuxtApp();
408
+ const { $dsl, $md } = useNuxtApp();
339
409
  return () => {
340
410
  const source = getLocalizedText(props.source, locale.value) ?? props.fallbackSource;
341
- return /* @__PURE__ */ jsx("div", { class: "relative w-full py-2 px-1 flex items-center justify-center text-xs", children: /* @__PURE__ */ jsx(
342
- "span",
411
+ const isEmpty = source.trim().length === 0;
412
+ const align = props.align === "center" || props.align === "right" ? props.align : "left";
413
+ const justifyClass = JUSTIFY_CLASS[isEmpty ? "center" : align];
414
+ const canCopy = props.copyable && typeof props.copyExpression === "string" && props.copyExpression.length > 0 && !isEmpty;
415
+ const onCopy = async () => {
416
+ if (!canCopy || !props.copyExpression) {
417
+ return;
418
+ }
419
+ try {
420
+ const text = String($dsl.evaluate`${props.copyExpression}`(props.dslContext));
421
+ await navigator.clipboard.writeText(text);
422
+ } catch (e) {
423
+ console.error(e);
424
+ }
425
+ };
426
+ return /* @__PURE__ */ jsxs(
427
+ "div",
343
428
  {
344
- class: "prose prose-zinc text-xs",
345
- innerHTML: $md.inline`${source}`({
346
- row: props.row,
347
- index: BigInt(props.index),
348
- id: props.id
349
- })
429
+ class: [
430
+ "relative w-full py-2 px-1 flex items-center text-xs group",
431
+ justifyClass,
432
+ isEmpty ? "text-zinc-300 select-none" : "text-zinc-600"
433
+ ],
434
+ children: [
435
+ isEmpty ? "-" : /* @__PURE__ */ jsx(
436
+ "span",
437
+ {
438
+ class: "prose prose-zinc text-xs",
439
+ innerHTML: $md.inline`${source}`({
440
+ row: props.row,
441
+ index: BigInt(props.index),
442
+ id: props.id
443
+ })
444
+ }
445
+ ),
446
+ canCopy ? /* @__PURE__ */ jsx(
447
+ Button,
448
+ {
449
+ "aria-label": getTableRendererConfigText("copy-cell-value"),
450
+ class: "p-1 w-6 h-6 flex items-center justify-center right-1 top-1/2 -translate-y-1/2 transform-3d group-hover:opacity-100 opacity-0 absolute transition-opacity duration-180",
451
+ size: "xs",
452
+ onClick: onCopy,
453
+ children: () => /* @__PURE__ */ jsx(Icon, { icon: "fluent:copy-20-regular" })
454
+ }
455
+ ) : null
456
+ ]
350
457
  }
351
- ) });
458
+ );
352
459
  };
353
460
  }
354
461
  });
@@ -567,18 +674,26 @@ defineTableRenderer(
567
674
  defineTableRenderer(
568
675
  "table.renderer.markdown",
569
676
  {
570
- source: localeC.optional()
677
+ source: localeC.optional(),
678
+ copyable: z.boolean().default(false),
679
+ copyExpression: z.string().nullable().optional().default(null),
680
+ align: z.enum(["left", "center", "right"]).default("left")
571
681
  },
572
682
  {
573
- cell: ({ ctx, options }) => {
683
+ cell: ({ ctx, dslContext, options }) => {
684
+ const rawValue = ctx.cell.getValue();
574
685
  return /* @__PURE__ */ jsx(
575
686
  TableRendererMarkdownCell,
576
687
  {
577
688
  source: options.source,
578
- fallbackSource: String(ctx.cell.getValue()),
689
+ fallbackSource: rawValue === void 0 || rawValue === null ? "" : String(rawValue),
579
690
  row: ctx.row.original,
580
691
  index: ctx.row.index,
581
- id: ctx.column.id
692
+ id: ctx.column.id,
693
+ dslContext,
694
+ copyable: options.copyable,
695
+ copyExpression: options.copyExpression,
696
+ align: options.align
582
697
  }
583
698
  );
584
699
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
- "version": "0.11.44",
3
+ "version": "0.11.46",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",