kanto-ds 1.6.1 → 1.7.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.
Files changed (65) hide show
  1. package/README.md +52 -4
  2. package/dist/cdn/kanto.min.js +6619 -0
  3. package/dist/chunks/{floating-B33g-M_1.js → floating-C9RLa6cZ.js} +2 -2
  4. package/dist/chunks/floating-C9RLa6cZ.js.map +1 -0
  5. package/dist/components/forms/kt-date-input/kt-date-input.js +1 -1
  6. package/dist/components/forms/kt-date-picker/kt-date-picker.js +1 -1
  7. package/dist/components/forms/kt-input/kt-input.js +1 -1
  8. package/dist/components/forms/kt-input-menu/kt-input-menu.js +1 -1
  9. package/dist/components/forms/kt-multi-select/kt-multi-select.js +1 -1
  10. package/dist/components/forms/kt-select/kt-select.js +1 -1
  11. package/dist/components/overlays/kt-dropdown/kt-dropdown.js +1 -1
  12. package/dist/docs/kt-alert.md +52 -0
  13. package/dist/docs/kt-avatar.md +46 -0
  14. package/dist/docs/kt-badge.md +104 -0
  15. package/dist/docs/kt-breadcrumb.md +53 -0
  16. package/dist/docs/kt-button.md +72 -0
  17. package/dist/docs/kt-calendar.md +98 -0
  18. package/dist/docs/kt-card.md +93 -0
  19. package/dist/docs/kt-chart.md +230 -0
  20. package/dist/docs/kt-checkbox.md +65 -0
  21. package/dist/docs/kt-code.md +88 -0
  22. package/dist/docs/kt-collapsible.md +50 -0
  23. package/dist/docs/kt-confirm-dialog.md +52 -0
  24. package/dist/docs/kt-date-input.md +97 -0
  25. package/dist/docs/kt-date-picker.md +116 -0
  26. package/dist/docs/kt-drag-drop.md +85 -0
  27. package/dist/docs/kt-dropdown.md +65 -0
  28. package/dist/docs/kt-empty-state.md +36 -0
  29. package/dist/docs/kt-form.md +93 -0
  30. package/dist/docs/kt-header.md +100 -0
  31. package/dist/docs/kt-icon.md +68 -0
  32. package/dist/docs/kt-input-menu.md +90 -0
  33. package/dist/docs/kt-input.md +137 -0
  34. package/dist/docs/kt-kbd.md +44 -0
  35. package/dist/docs/kt-label-input.md +54 -0
  36. package/dist/docs/kt-meter.md +79 -0
  37. package/dist/docs/kt-modal.md +62 -0
  38. package/dist/docs/kt-multi-select.md +115 -0
  39. package/dist/docs/kt-page-header.md +53 -0
  40. package/dist/docs/kt-pagination.md +36 -0
  41. package/dist/docs/kt-progress-bar.md +66 -0
  42. package/dist/docs/kt-radio-group.md +73 -0
  43. package/dist/docs/kt-segmented-control.md +70 -0
  44. package/dist/docs/kt-select.md +80 -0
  45. package/dist/docs/kt-side-panel.md +59 -0
  46. package/dist/docs/kt-skeleton.md +46 -0
  47. package/dist/docs/kt-split-button.md +105 -0
  48. package/dist/docs/kt-stat.md +57 -0
  49. package/dist/docs/kt-sub-menu-navigation.md +118 -0
  50. package/dist/docs/kt-table.md +179 -0
  51. package/dist/docs/kt-tabs.md +87 -0
  52. package/dist/docs/kt-textarea.md +59 -0
  53. package/dist/docs/kt-time-input.md +88 -0
  54. package/dist/docs/kt-timeline.md +63 -0
  55. package/dist/docs/kt-toast-container.md +69 -0
  56. package/dist/docs/kt-toast.md +41 -0
  57. package/dist/docs/kt-toggle-button-group.md +67 -0
  58. package/dist/docs/kt-toggle-button.md +52 -0
  59. package/dist/docs/kt-toggle.md +47 -0
  60. package/dist/docs/kt-tooltip.md +68 -0
  61. package/dist/internal/floating.d.ts +4 -0
  62. package/dist/tokens/colors.css +5 -2
  63. package/dist/web-types.json +1 -1
  64. package/package.json +23 -5
  65. package/dist/chunks/floating-B33g-M_1.js.map +0 -1
@@ -0,0 +1,52 @@
1
+ # `<kt-toggle-button>`
2
+
3
+ A button that stays pressed.
4
+
5
+ ```html
6
+ <kt-toggle-button icon="bold" label="Bold"></kt-toggle-button>
7
+ <kt-toggle-button variant="outline" value="draft">Draft</kt-toggle-button>
8
+ ```
9
+
10
+ `aria-pressed`, not `aria-checked`: this is a control holding a state, not one
11
+ option among several. When they _are_ options among several and only one may be
12
+ active, reach for [`<kt-segmented-control>`](./kt-segmented-control.md)
13
+ or [`<kt-tabs>`](./kt-tabs.md) — they carry the right semantics and the
14
+ right keyboard model.
15
+
16
+ To draw several as one bar, wrap them in
17
+ [`<kt-toggle-button-group>`](./kt-toggle-button-group.md).
18
+ Inside a group the button becomes controlled: it stops flipping itself and stops
19
+ emitting, and the group drives it.
20
+
21
+ ## Variants
22
+
23
+ | Variant | Resting |
24
+ | ----------- | ------------------------------------------ |
25
+ | `primary` | Raised surface; solid indigo when pressed |
26
+ | `secondary` | Flat; soft indigo tint when pressed |
27
+ | `outline` | Bordered, transparent; tinted when pressed |
28
+
29
+ ## API
30
+
31
+ | Property | Attribute | Type | Default |
32
+ | -------------- | --------------- | --------------------------------------- | ----------- |
33
+ | `selected` | `selected` | `boolean` | `false` |
34
+ | `disabled` | `disabled` | `boolean` | `false` |
35
+ | `variant` | `variant` | `'primary' \| 'secondary' \| 'outline'` | `'primary'` |
36
+ | `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
37
+ | `value` | `value` | `string` | `''` |
38
+ | `icon` | `icon` | `string` | `''` |
39
+ | `iconPosition` | `icon-position` | `'left' \| 'right'` | `'left'` |
40
+ | `label` | `label` | `string` | `''` |
41
+
42
+ | Event | Detail |
43
+ | ----------- | ------------------------------------------------ |
44
+ | `kt-change` | `{ selected, value }` — not fired inside a group |
45
+
46
+ | Slot | Description |
47
+ | --------- | ---------------- |
48
+ | _default_ | The button label |
49
+
50
+ | Part | Description |
51
+ | -------- | --------------------- |
52
+ | `button` | The native `<button>` |
@@ -0,0 +1,47 @@
1
+ # `<kt-toggle>`
2
+
3
+ An on/off switch.
4
+
5
+ ```html
6
+ <kt-toggle checked>Notifications</kt-toggle>
7
+ <kt-toggle size="small" label="Dark mode"></kt-toggle>
8
+ <kt-toggle disabled></kt-toggle>
9
+ ```
10
+
11
+ ## Sizing
12
+
13
+ The switch is derived from the field height rather than given fixed pixels:
14
+ the track is 1.8× `--switch-height`, and the thumb is inset by 12% of it. So a
15
+ toggle lines up with the inputs and buttons next to it, at every size and every
16
+ breakpoint, and overriding `--button-height` moves all of them together.
17
+
18
+ ## Switch, not checkbox
19
+
20
+ `role="switch"` with `aria-checked`, which screen readers announce as "on"/"off"
21
+ rather than "checked". Use it for a setting that takes effect immediately. For
22
+ something that only applies when a form is submitted, a checkbox is the honest
23
+ control.
24
+
25
+ In a form, an unchecked toggle contributes **nothing** to the submission and a
26
+ checked one contributes its `value` — the same rule as a native checkbox.
27
+
28
+ ## API
29
+
30
+ | Property | Attribute | Type | Default |
31
+ | ---------- | ---------- | -------------------------------- | ---------- |
32
+ | `checked` | `checked` | `boolean` | `false` |
33
+ | `disabled` | `disabled` | `boolean` | `false` |
34
+ | `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
35
+ | `name` | `name` | `string` | `''` |
36
+ | `value` | `value` | `string` | `'on'` |
37
+ | `label` | `label` | `string` | `''` |
38
+
39
+ | Event | Detail |
40
+ | ----------- | ---------------------- |
41
+ | `kt-change` | `{ checked: boolean }` |
42
+
43
+ | Part | Description |
44
+ | ------- | -------------------------- |
45
+ | `base` | The `role="switch"` button |
46
+ | `track` | The track |
47
+ | `thumb` | The sliding thumb |
@@ -0,0 +1,68 @@
1
+ # `<kt-tooltip>`
2
+
3
+ A short label that appears on hover or focus. Wrap what it describes:
4
+
5
+ ```html
6
+ <kt-tooltip text="Refresh the data">
7
+ <kt-button icon="refresh-cw" label="Refresh"></kt-button>
8
+ </kt-tooltip>
9
+ ```
10
+
11
+ ## A tooltip is a description, not a name
12
+
13
+ Note the `label` on the button above. A tooltip supplements a control; it must
14
+ never be the only thing naming it. A tooltip that has to be hovered to be read
15
+ leaves touch users and screen-reader users with an unlabelled button.
16
+
17
+ The rule: if the trigger has no visible text, it needs its own accessible name,
18
+ and the tooltip adds detail on top.
19
+
20
+ ## How the description reaches the trigger
21
+
22
+ `aria-describedby` cannot cross a shadow boundary — an id inside this element's
23
+ shadow root is invisible to a trigger sitting in the light DOM.
24
+
25
+ So `<kt-tooltip>` also puts the text in a light-DOM node, addressed to a slot
26
+ that does not exist. That keeps it out of the rendered output while leaving it
27
+ referenceable: an explicit `aria-describedby` target is read even when it is not
28
+ displayed.
29
+
30
+ ## Where the bubble goes
31
+
32
+ The bubble is a popover in the top layer, placed from the trigger in viewport
33
+ coordinates. No ancestor's `overflow: hidden` can clip it, and it takes no room
34
+ in the page.
35
+
36
+ `placement` is a preference. When that side has no room — `top` on an icon at
37
+ the top of the page — the bubble takes the opposite side, and it slides along
38
+ its side to stay inside the screen. Scrolling or resizing hides it, since a
39
+ bubble fixed to the viewport would drift away from its trigger.
40
+
41
+ ## Holding it open
42
+
43
+ `open` shows the bubble whatever the pointer does. It is for a trigger that
44
+ cannot take focus itself: `<kt-input>` holds its error icon's tooltip open while
45
+ the field has focus, so a keyboard user sees the message a mouse user gets on
46
+ hover.
47
+
48
+ ## Dismissal
49
+
50
+ Escape hides the tooltip while the trigger keeps focus, as WCAG 1.4.13 requires
51
+ of any content shown on hover or focus.
52
+
53
+ ## API
54
+
55
+ | Property | Attribute | Type | Default |
56
+ | ----------- | ----------- | ---------------------------------------- | ------- |
57
+ | `text` | `text` | `string` | `''` |
58
+ | `placement` | `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` |
59
+ | `disabled` | `disabled` | `boolean` | `false` |
60
+ | `open` | `open` | `boolean` | `false` |
61
+
62
+ | Slot | Description |
63
+ | --------- | ----------- |
64
+ | _default_ | The trigger |
65
+
66
+ | Part | Description |
67
+ | -------- | ------------------ |
68
+ | `bubble` | The tooltip bubble |
@@ -29,6 +29,10 @@ export interface FloatingOptions {
29
29
  * animatable state its element gives it, so it can fade out after it leaves
30
30
  * the top layer: `display` here only undoes the popover's `display: none`, and
31
31
  * a panel's own `display` still wins.
32
+ *
33
+ * Until it is first placed it sits top left. With auto insets a closed panel
34
+ * sat where the flow put it — beside a right-hand trigger, past the edge of
35
+ * the page, which then scrolled sideways.
32
36
  */
33
37
  export declare const floatingStyles: import("lit").CSSResult;
34
38
  export declare class FloatingController implements ReactiveController {
@@ -56,9 +56,12 @@
56
56
  --color-success-soft: rgba(53, 221, 131, 0.12);
57
57
 
58
58
  /* === TEXT STEPS OF THE BRAND AND SEMANTIC COLOURS === */
59
+ /* Info and danger are a shade lighter than the rest need: an alert's action
60
+ button lays its tint on the alert's, and on a card that double tint is the
61
+ lightest ground these text steps meet. */
59
62
  --color-primary-text: var(--accent-text-dark, #8e97ff);
60
- --color-danger-text: #ff727f;
61
- --color-info-text: #06b0fc;
63
+ --color-danger-text: #ff7984;
64
+ --color-info-text: #43bbff;
62
65
  --color-warning-text: #fca80d;
63
66
  --color-success-text: #01df7e;
64
67
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "kanto-ds",
4
- "version": "1.6.1",
4
+ "version": "1.7.0",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
package/package.json CHANGED
@@ -1,14 +1,29 @@
1
1
  {
2
2
  "name": "kanto-ds",
3
- "version": "1.6.1",
4
- "description": "Framework-agnostic design system for data-dense product interfaces.",
3
+ "version": "1.7.0",
4
+ "description": "Forty-nine accessible web components for dashboards, admin tools and forms — themeable in one line, in React, Vue, Angular, Svelte or plain HTML.",
5
5
  "keywords": [
6
6
  "design-system",
7
7
  "web-components",
8
8
  "custom-elements",
9
9
  "lit",
10
10
  "ui",
11
- "dark-theme"
11
+ "ui-kit",
12
+ "components",
13
+ "dashboard",
14
+ "admin",
15
+ "forms",
16
+ "data-table",
17
+ "date-picker",
18
+ "react",
19
+ "vue",
20
+ "angular",
21
+ "svelte",
22
+ "accessible",
23
+ "a11y",
24
+ "theming",
25
+ "dark-theme",
26
+ "dark-mode"
12
27
  ],
13
28
  "homepage": "https://kanto.arnaudmichel.fr",
14
29
  "bugs": {
@@ -37,6 +52,8 @@
37
52
  },
38
53
  "main": "./dist/index.js",
39
54
  "module": "./dist/index.js",
55
+ "unpkg": "./dist/cdn/kanto.min.js",
56
+ "jsdelivr": "./dist/cdn/kanto.min.js",
40
57
  "types": "./dist/index.d.ts",
41
58
  "customElements": "./dist/custom-elements.json",
42
59
  "web-types": "./dist/web-types.json",
@@ -286,10 +303,11 @@
286
303
  ],
287
304
  "scripts": {
288
305
  "dev": "vite --config demo/vite.config.ts",
289
- "build": "npm run build:js && npm run build:types && npm run build:static && npm run build:manifest",
306
+ "build": "npm run build:js && npm run build:cdn && npm run build:types && npm run build:static && npm run build:manifest",
307
+ "build:cdn": "node scripts/build-cdn.js",
290
308
  "build:js": "vite build",
291
309
  "build:types": "tsc -p tsconfig.build.json",
292
- "build:static": "node scripts/copy-static.js",
310
+ "build:static": "node scripts/copy-static.js && node scripts/llms.js --docs",
293
311
  "build:manifest": "cem analyze --config custom-elements-manifest.config.js",
294
312
  "build:demo": "vite build --config demo/vite.config.ts",
295
313
  "test": "vitest run",
@@ -1 +0,0 @@
1
- {"version":3,"file":"floating-B33g-M_1.js","sources":["../../src/internal/floating.ts"],"sourcesContent":["import { css, type ReactiveController, type ReactiveControllerHost } from 'lit';\nimport { placeFloating, type Align, type Side } from './position.js';\n\n/**\n * A panel that opens from a trigger — a select's list, a date picker's\n * calendar, a menu — drawn in the top layer and placed from the trigger.\n *\n * A panel positioned inside its element was cut off by any ancestor with\n * `overflow: hidden`: a table cell, a side panel, an app's scrolling main\n * area. In the top layer, nothing clips it. It opens on the side asked for, or\n * the other one when that has no room, and follows the trigger as the page\n * scrolls.\n */\n\nexport interface FloatingOptions {\n /** The panel, which carries `popover=\"manual\"` and the `floating` class. */\n readonly panel: () => HTMLElement | null | undefined;\n /** What the panel opens from. */\n readonly anchor: () => Element | null | undefined;\n /** The side it prefers. */\n readonly side?: () => Side;\n /** Which edge of the anchor it lines up with; its start by default. */\n readonly align?: () => Align;\n /** Sizes the panel to the anchor's width — a list under its field. */\n readonly matchWidth?: boolean;\n /** Told the side it opened on, for the direction of its entrance. */\n readonly onPlace?: (side: Side) => void;\n}\n\n/**\n * The panel's own styles. Closed, it keeps the display and the hidden,\n * animatable state its element gives it, so it can fade out after it leaves\n * the top layer: `display` here only undoes the popover's `display: none`, and\n * a panel's own `display` still wins.\n */\nexport const floatingStyles = css`\n .floating {\n position: fixed;\n inset: auto;\n display: block;\n /* As wide as what it holds, wherever it is placed: a box sized from its\n position would change size when moved, and be moved again. */\n width: max-content;\n margin: 0;\n color: inherit;\n /* Set apart from the page by the theme: a lighter surface in the dark,\n an edge and a soft shadow in the light. */\n border: var(--border-width) solid var(--border-popover);\n box-shadow: var(--shadow-popover);\n }\n`;\n\nexport class FloatingController implements ReactiveController {\n private open = false;\n private frame = 0;\n /** Places the panel again when its size changes — content drawn after it opened. */\n private resizeObserver: ResizeObserver | undefined;\n\n constructor(\n host: ReactiveControllerHost,\n private readonly options: FloatingOptions,\n ) {\n host.addController(this);\n }\n\n /**\n * Call from the host's `updated()` with whether the panel is open. While it\n * is, every update re-places it: its content — a filtered list — can change\n * its size.\n */\n sync(open: boolean): void {\n // First, and whatever the panel: one rendered only while open is already\n // gone when it closes, and its listeners must go with it.\n if (open !== this.open) {\n this.open = open;\n const method = open ? 'addEventListener' : 'removeEventListener';\n window[method]('scroll', this.follow, { capture: true, passive: true });\n window[method]('resize', this.follow);\n }\n\n const panel = this.options.panel();\n // Where popovers are missing — a test DOM — the panel stays where it is.\n if (!panel || typeof panel.showPopover !== 'function') return;\n\n if (open) {\n if (!panel.matches(':popover-open')) panel.showPopover();\n this.place();\n // A panel measured at opening may grow once what it holds has drawn —\n // a calendar is an element of its own — and must be placed again.\n if (!this.resizeObserver && typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(this.follow);\n this.resizeObserver.observe(panel);\n }\n } else {\n this.unobserve();\n if (panel.matches(':popover-open')) panel.hidePopover();\n }\n }\n\n private unobserve(): void {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n }\n\n hostDisconnected(): void {\n this.sync(false);\n this.unobserve();\n cancelAnimationFrame(this.frame);\n }\n\n private follow = (): void => {\n cancelAnimationFrame(this.frame);\n this.frame = requestAnimationFrame(() => this.place());\n };\n\n private place(): void {\n const panel = this.options.panel();\n const anchor = this.options.anchor()?.getBoundingClientRect();\n if (!panel || !anchor) return;\n\n if (this.options.matchWidth) panel.style.width = `${anchor.width}px`;\n // Untransformed size: the entrance animation scales and slides the panel.\n const { x, y, placement } = placeFloating(\n anchor,\n { width: panel.offsetWidth, height: panel.offsetHeight },\n { width: window.innerWidth, height: window.innerHeight },\n this.options.side?.() ?? 'bottom',\n this.options.align?.() ?? 'start',\n );\n panel.style.left = `${x}px`;\n panel.style.top = `${y}px`;\n this.options.onPlace?.(placement);\n }\n}\n"],"names":["floatingStyles","css","FloatingController","host","options","open","method","panel","anchor","x","y","placement","placeFloating"],"mappings":";;AAmCO,MAAMA,IAAiBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBvB,MAAMC,EAAiD;AAAA,EAM5D,YACEC,GACiBC,GACjB;AADiB,SAAA,UAAAA,GAPnB,KAAQ,OAAO,IACf,KAAQ,QAAQ,GAwDhB,KAAQ,SAAS,MAAY;AAC3B,2BAAqB,KAAK,KAAK,GAC/B,KAAK,QAAQ,sBAAsB,MAAM,KAAK,OAAO;AAAA,IACvD,GAnDED,EAAK,cAAc,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAKE,GAAqB;AAGxB,QAAIA,MAAS,KAAK,MAAM;AACtB,WAAK,OAAOA;AACZ,YAAMC,IAASD,IAAO,qBAAqB;AAC3C,aAAOC,CAAM,EAAE,UAAU,KAAK,QAAQ,EAAE,SAAS,IAAM,SAAS,IAAM,GACtE,OAAOA,CAAM,EAAE,UAAU,KAAK,MAAM;AAAA,IACtC;AAEA,UAAMC,IAAQ,KAAK,QAAQ,MAAA;AAE3B,IAAI,CAACA,KAAS,OAAOA,EAAM,eAAgB,eAEvCF,KACGE,EAAM,QAAQ,eAAe,OAAS,YAAA,GAC3C,KAAK,MAAA,GAGD,CAAC,KAAK,kBAAkB,OAAO,iBAAmB,QACpD,KAAK,iBAAiB,IAAI,eAAe,KAAK,MAAM,GACpD,KAAK,eAAe,QAAQA,CAAK,OAGnC,KAAK,UAAA,GACDA,EAAM,QAAQ,eAAe,OAAS,YAAA;AAAA,EAE9C;AAAA,EAEQ,YAAkB;AACxB,SAAK,gBAAgB,WAAA,GACrB,KAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,mBAAyB;AACvB,SAAK,KAAK,EAAK,GACf,KAAK,UAAA,GACL,qBAAqB,KAAK,KAAK;AAAA,EACjC;AAAA,EAOQ,QAAc;AACpB,UAAMA,IAAQ,KAAK,QAAQ,MAAA,GACrBC,IAAS,KAAK,QAAQ,OAAA,GAAU,sBAAA;AACtC,QAAI,CAACD,KAAS,CAACC,EAAQ;AAEvB,IAAI,KAAK,QAAQ,eAAYD,EAAM,MAAM,QAAQ,GAAGC,EAAO,KAAK;AAEhE,UAAM,EAAE,GAAAC,GAAG,GAAAC,GAAG,WAAAC,EAAA,IAAcC;AAAA,MAC1BJ;AAAA,MACA,EAAE,OAAOD,EAAM,aAAa,QAAQA,EAAM,aAAA;AAAA,MAC1C,EAAE,OAAO,OAAO,YAAY,QAAQ,OAAO,YAAA;AAAA,MAC3C,KAAK,QAAQ,OAAA,KAAY;AAAA,MACzB,KAAK,QAAQ,aAAa;AAAA,IAAA;AAE5B,IAAAA,EAAM,MAAM,OAAO,GAAGE,CAAC,MACvBF,EAAM,MAAM,MAAM,GAAGG,CAAC,MACtB,KAAK,QAAQ,UAAUC,CAAS;AAAA,EAClC;AACF;"}