@kungal/ui-core 2.54.0 → 2.56.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/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # @kungal/ui-core
2
2
 
3
+ ## 2.56.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 570067b: Coloured text and placeholders now clear WCAG AA (4.5:1). A kungal Flutter app's contrast check measured KunUI's own coloured text and placeholders below it, and the web uses the same classes.
8
+
9
+ **New tokens:**
10
+
11
+ - `--color-{color}-text` (Tailwind `text-primary-text`, `text-danger-text`, …), one per semantic colour, `default` included.
12
+ - In Dart: `KunColorScale.text`.
13
+
14
+ **Why a new token.** A fill colour used as text measured 1.75–4.42:1 on the light page for every colour but `default`, and in dark mode primary and danger fell to 3.87:1 and 3.66:1 on cards. `{color}-text` is the ramp step closest to the fill that clears 4.5:1 on:
15
+
16
+ - the page background;
17
+ - cards (`content1`);
18
+ - the colour's own 20% tint over each, which is the hover and keyboard-focus fill of a light item and the fill of a flat chip.
19
+
20
+ The token generator measures all four in both modes and fails the build if one misses. The steps it picks:
21
+
22
+ | Mode | Step 600 | Step 700 |
23
+ | ----- | ----------------------------- | --------------------------------------- |
24
+ | Light | secondary, warning | primary, success, danger, info, default |
25
+ | Dark | every colour except secondary | secondary |
26
+
27
+ **What moved to it:**
28
+
29
+ - The `light`, `bordered` and `flat` variants (buttons, chips, badges, menu items) and `kunTextClasses`, which covers KunLink, selected tabs, active steps and reactions.
30
+ - KunInfo's `bordered` text, and its dark `flat` danger and info.
31
+ - Every form error message and required asterisk.
32
+ - Chat sender names, reply and pinned titles, links, mentions, typing and status text.
33
+
34
+ **What you'll see.** Coloured text is one step darker in light mode and one step lighter in dark mode. Icons, SVG strokes, spinners and text on solid fills keep their colours.
35
+
36
+ **If your own markup uses `text-primary` for readable text**, switch it to `text-primary-text`. `text-primary` stays the fill colour, meant for fills, borders and icons.
37
+
38
+ **Placeholders** now use `foreground-muted`, the secondary-text colour: 5.52:1 light and 4.85:1 dark, where `default-400` measured 2.31–3.58:1. This covers the base-layer `::placeholder` rule (every native input), KunSelect's and KunDatePicker's empty trigger, KunChatComposer and KunCommandPalette. A placeholder is often the only label a field has, such as "全部平台" in a filter. Disabled text, outside-month days and icons keep their lighter steps: WCAG exempts disabled controls, and the others are not text.
39
+
40
+ Measured on the docs site in Chromium: 227 text elements in each mode across the button, chip, tab, link, select, input, info, dropdown, chat bubble, date picker and textarea pages all clear 4.5:1. The lowest are a warning chip (4.77:1 light, 4.87:1 dark) and the dark placeholder (4.85:1).
41
+
42
+ ## 2.55.0
43
+
44
+ ### Minor Changes
45
+
46
+ - 0bac099: New `KunSplitPane`: two panes with a divider you can drag or move with the keyboard. It suits a list beside a detail view, or a main area with an auxiliary column. KunChatLayout now switches between one and two panes by its own width, and its list pane can be made draggable.
47
+
48
+ **KunSplitPane** puts its panes in the `#start` and `#end` slots.
49
+
50
+ - **Width.** `v-model:size` is the primary pane's width in px (default 360). It is a prop the server knows, so the server-rendered HTML already has the layout and the divider's `aria-valuenow`/`min`/`max`.
51
+ - **Persisting the width.** `v-model:size` updates on every pointer move. Save from `resize-end`, which fires once per drag or key press, for example to a cookie your server reads back into `size`.
52
+ - **Limits and snapping.** `min-size` and `max-size` default to 240 and 480. `snap-points` (e.g. `[360, 412]`) pull the divider in once it comes within `snap-threshold` px (default 8), and any width in between stays reachable. A keyboard step that ends within the threshold snaps too, but a snap never cancels or reverses a step, so a small `step` cannot get stuck on a snap point.
53
+ - **Which pane is sized.** `primary="end"` gives the width to the right pane, for an auxiliary column.
54
+ - **Keyboard** (WAI-ARIA window splitter pattern):
55
+ - ← and → move the divider by `step` (default 10px); Shift moves five steps.
56
+ - Home and End jump to the minimum and maximum.
57
+ - **The divider** is a 1px line. Its grab area is 9px wide with a mouse and 21px on a touch screen, and it sits above the panes' content. A drag follows the pointer that started it; a second finger or the mouse cannot take it over. While you drag, the page keeps a col-resize cursor, no text gets selected, and the panes ignore the pointer, so an iframe can't swallow the drag.
58
+ - **Narrow layouts.** Below `stack-below` (`md` = 48rem by default, `lg` = 64rem, or `false`), it shows one pane at a time, chosen by `show-pane`. This is a container query on the component's own width, not a media query on the window: a split nested beside a side rail or inside another pane stacks based on the room it actually has.
59
+ - **Flutter port.** The snapping rule is a pure `resolveKunSplitSize` in `@kungal/ui-core`, with tests.
60
+
61
+ **KunChatLayout** now shows two panes once the layout itself is 48rem (768px) wide, rather than once the window is.
62
+
63
+ - **Why:** a chat beside an app's side rail used to switch to two panes in a 768px window that left it 679px, and the conversation was squeezed to 327px.
64
+ - **What might change for you:** pages that give the chat less than 48rem (for example, a window of about 768–800px minus page padding) now show one pane.
65
+ - **KunChatHeader's `back="mobile"`** follows the KunChatLayout around it. Outside a KunChatLayout it still uses the window's `md` width.
66
+ - **New props:** `resizable`, `v-model:sidebar-size` (px), `sidebar-min-size` and `sidebar-max-size` make the list draggable through KunSplitPane. The `sidebar-resize-end` event is the one to persist from. Without `resizable`, `sidebar-width` works as before.
67
+
3
68
  ## 2.54.0
4
69
 
5
70
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -54,32 +54,35 @@ var TABLE = {
54
54
  danger: "border border-transparent bg-danger text-danger-foreground",
55
55
  info: "border border-transparent bg-info text-info-foreground"
56
56
  },
57
+ // `{c}-text`, not the fill: a fill used as text measured 1.75–4.42:1 on the
58
+ // light page. The generator holds `{c}-text` at 4.5:1 on the page, on cards
59
+ // and on the hue's 20% tint, so the hover fill and a flat chip stay readable.
57
60
  bordered: {
58
61
  default: "border border-default bg-transparent",
59
- primary: "border border-primary bg-transparent text-primary",
60
- secondary: "border border-secondary bg-transparent text-secondary",
61
- success: "border border-success bg-transparent text-success",
62
- warning: "border border-warning bg-transparent text-warning",
63
- danger: "border border-danger bg-transparent text-danger",
64
- info: "border border-info bg-transparent text-info"
62
+ primary: "border border-primary bg-transparent text-primary-text",
63
+ secondary: "border border-secondary bg-transparent text-secondary-text",
64
+ success: "border border-success bg-transparent text-success-text",
65
+ warning: "border border-warning bg-transparent text-warning-text",
66
+ danger: "border border-danger bg-transparent text-danger-text",
67
+ info: "border border-info bg-transparent text-info-text"
65
68
  },
66
69
  light: {
67
70
  default: "border border-transparent bg-transparent hover:bg-default/20",
68
- primary: "border border-transparent bg-transparent text-primary hover:bg-primary/20",
69
- secondary: "border border-transparent bg-transparent text-secondary hover:bg-secondary/20",
70
- success: "border border-transparent bg-transparent text-success hover:bg-success/20",
71
- warning: "border border-transparent bg-transparent text-warning hover:bg-warning/20",
72
- danger: "border border-transparent bg-transparent text-danger hover:bg-danger/20",
73
- info: "border border-transparent bg-transparent text-info hover:bg-info/20"
71
+ primary: "border border-transparent bg-transparent text-primary-text hover:bg-primary/20",
72
+ secondary: "border border-transparent bg-transparent text-secondary-text hover:bg-secondary/20",
73
+ success: "border border-transparent bg-transparent text-success-text hover:bg-success/20",
74
+ warning: "border border-transparent bg-transparent text-warning-text hover:bg-warning/20",
75
+ danger: "border border-transparent bg-transparent text-danger-text hover:bg-danger/20",
76
+ info: "border border-transparent bg-transparent text-info-text hover:bg-info/20"
74
77
  },
75
78
  flat: {
76
- default: "border border-transparent bg-default/20 text-default-700",
77
- primary: "border border-transparent bg-primary/20 text-primary-600",
78
- secondary: "border border-transparent bg-secondary/20 text-secondary-600",
79
- success: "border border-transparent bg-success/20 text-success-700 dark:text-success",
80
- warning: "border border-transparent bg-warning/20 text-warning-700 dark:text-warning",
81
- danger: "border border-transparent bg-danger/20 text-danger-600 dark:text-danger-500",
82
- info: "border border-transparent bg-info/20 text-info-700 dark:text-info-500"
79
+ default: "border border-transparent bg-default/20 text-default-text",
80
+ primary: "border border-transparent bg-primary/20 text-primary-text",
81
+ secondary: "border border-transparent bg-secondary/20 text-secondary-text",
82
+ success: "border border-transparent bg-success/20 text-success-text",
83
+ warning: "border border-transparent bg-warning/20 text-warning-text",
84
+ danger: "border border-transparent bg-danger/20 text-danger-text",
85
+ info: "border border-transparent bg-info/20 text-info-text"
83
86
  },
84
87
  // Same fill logic as `solid` (see note above) plus a COLORED glow. The glow
85
88
  // needs both a size (`shadow-lg` — the geometry) AND a tint (`shadow-{color}/40`
@@ -135,12 +138,12 @@ var kunSolidClasses = {
135
138
  };
136
139
  var kunTextClasses = {
137
140
  default: "text-foreground",
138
- primary: "text-primary",
139
- secondary: "text-secondary",
140
- success: "text-success",
141
- warning: "text-warning",
142
- danger: "text-danger",
143
- info: "text-info"
141
+ primary: "text-primary-text",
142
+ secondary: "text-secondary-text",
143
+ success: "text-success-text",
144
+ warning: "text-warning-text",
145
+ danger: "text-danger-text",
146
+ info: "text-info-text"
144
147
  };
145
148
  var kunBorderClasses = {
146
149
  default: "border-default",
@@ -541,6 +544,9 @@ var zh_CN_default = {
541
544
  clear: "清除",
542
545
  removeOption: "移除 {label}"
543
546
  },
547
+ splitPane: {
548
+ handle: "调整分栏宽度"
549
+ },
544
550
  spoiler: {
545
551
  copyCode: "复制代码",
546
552
  reveal: "剧透内容,点击或按回车显示"
@@ -684,6 +690,25 @@ var normalizeKunMenuSeparators = (entries) => {
684
690
  return out;
685
691
  };
686
692
 
693
+ // src/splitPane.ts
694
+ var resolveKunSplitSize = (raw, { min, max, snapPoints = [], snapThreshold = 8, from }) => {
695
+ const lo = Math.min(min, max);
696
+ const hi = Math.max(min, max);
697
+ const clamped = Math.min(Math.max(raw, lo), hi);
698
+ let best = clamped;
699
+ let bestDistance = Infinity;
700
+ for (const point of snapPoints) {
701
+ if (point < lo || point > hi) continue;
702
+ const distance = Math.abs(point - clamped);
703
+ if (distance <= snapThreshold && distance < bestDistance) {
704
+ best = point;
705
+ bestDistance = distance;
706
+ }
707
+ }
708
+ if (from !== void 0 && Math.sign(best - from) !== Math.sign(clamped - from)) best = clamped;
709
+ return Math.round(best);
710
+ };
711
+
687
712
  // src/random.ts
688
713
  var randomNum = (lowerValue, upperValue) => Math.floor(Math.random() * (upperValue - lowerValue + 1) + lowerValue);
689
714
 
@@ -1749,6 +1774,7 @@ exports.randomNum = randomNum;
1749
1774
  exports.registerKunIcon = registerKunIcon;
1750
1775
  exports.registerKunIcons = registerKunIcons;
1751
1776
  exports.resolveKunShortcut = resolveKunShortcut;
1777
+ exports.resolveKunSplitSize = resolveKunSplitSize;
1752
1778
  exports.resolveRounded = resolveRounded;
1753
1779
  exports.sliceKunChatEntities = sliceKunChatEntities;
1754
1780
  exports.speakKunShortcut = speakKunShortcut;