@zeyos/zx 2.2.1 → 3.0.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 (117) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/DESIGN-SYSTEM.md +136 -0
  3. package/MIGRATION.md +155 -4
  4. package/README.md +51 -14
  5. package/dist/types/compat/map/data.d.ts +3 -2
  6. package/dist/types/components/account-menu/account-menu.d.ts +144 -0
  7. package/dist/types/components/app-rail/app-rail.d.ts +250 -0
  8. package/dist/types/components/app-sidebar/app-sidebar.d.ts +169 -0
  9. package/dist/types/components/avatar/avatar.d.ts +100 -0
  10. package/dist/types/components/chart/chart.d.ts +321 -0
  11. package/dist/types/components/date-picker/month-picker.d.ts +6 -0
  12. package/dist/types/components/dialog/dialog.d.ts +9 -0
  13. package/dist/types/components/dock/dock.d.ts +495 -0
  14. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  15. package/dist/types/components/field/field.d.ts +14 -0
  16. package/dist/types/components/field-upload/field-upload.d.ts +37 -4
  17. package/dist/types/components/form/form.d.ts +25 -3
  18. package/dist/types/components/grid/grid.d.ts +172 -0
  19. package/dist/types/components/launcher/launcher.d.ts +300 -0
  20. package/dist/types/components/layout/layout.d.ts +4 -4
  21. package/dist/types/components/menu-button/menu-button.d.ts +10 -2
  22. package/dist/types/components/modal/modal.d.ts +25 -0
  23. package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +74 -9
  24. package/dist/types/components/questionnaire/items.d.ts +327 -0
  25. package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
  26. package/dist/types/components/select/select.d.ts +36 -1
  27. package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
  28. package/dist/types/components/sheet/sheet.d.ts +294 -0
  29. package/dist/types/components/split-view/split-view.d.ts +2 -21
  30. package/dist/types/components/tabbox/tabbox.d.ts +12 -3
  31. package/dist/types/components/table/table.d.ts +219 -12
  32. package/dist/types/components/tooltip/tooltip.d.ts +2 -2
  33. package/dist/types/components/value-list/value-list.d.ts +24 -3
  34. package/dist/types/core/dom.d.ts +114 -0
  35. package/dist/types/core/drag-axis.d.ts +111 -0
  36. package/dist/types/core/position.d.ts +4 -2
  37. package/dist/types/index.d.ts +12 -2
  38. package/dist/zx-compat.esm.js +943 -311
  39. package/dist/zx-compat.esm.min.js +1 -1
  40. package/dist/zx-compat.global.js +7893 -2252
  41. package/dist/zx-compat.global.min.js +3 -3
  42. package/dist/zx-zeyos.esm.js +826 -114
  43. package/dist/zx-zeyos.esm.min.js +1 -1
  44. package/dist/zx.css +1720 -243
  45. package/dist/zx.esm.js +8227 -2599
  46. package/dist/zx.esm.min.js +3 -3
  47. package/dist/zx.global.js +8227 -2599
  48. package/dist/zx.global.min.js +3 -3
  49. package/dist/zx.min.css +1 -1
  50. package/docs/api.json +2597 -255
  51. package/docs/llms.md +475 -37
  52. package/docs/llms.txt +21 -9
  53. package/package.json +4 -2
  54. package/src/compat/globals.js +3 -1
  55. package/src/compat/map/data.js +31 -9
  56. package/src/components/account-menu/account-menu.css +70 -0
  57. package/src/components/account-menu/account-menu.js +208 -0
  58. package/src/components/app-rail/app-rail.css +107 -0
  59. package/src/components/app-rail/app-rail.js +668 -0
  60. package/src/components/app-sidebar/app-sidebar.css +68 -0
  61. package/src/components/app-sidebar/app-sidebar.js +388 -0
  62. package/src/components/avatar/avatar.css +61 -0
  63. package/src/components/avatar/avatar.js +222 -0
  64. package/src/components/button/button.css +0 -1
  65. package/src/components/chart/chart.css +61 -0
  66. package/src/components/chart/chart.js +518 -0
  67. package/src/components/date-picker/date-range-picker.css +7 -0
  68. package/src/components/date-picker/month-picker.js +9 -0
  69. package/src/components/dialog/dialog.js +11 -4
  70. package/src/components/dock/dock.css +228 -0
  71. package/src/components/dock/dock.js +977 -0
  72. package/src/components/dropdown/dropdown.js +1 -1
  73. package/src/components/field/field.js +2 -0
  74. package/src/components/field-upload/field-upload.js +9 -4
  75. package/src/components/fieldset/fieldset.css +7 -0
  76. package/src/components/form/form.css +7 -0
  77. package/src/components/form/form.js +6 -3
  78. package/src/components/grid/grid.css +6 -0
  79. package/src/components/grid/grid.js +213 -0
  80. package/src/components/launcher/launcher.css +100 -0
  81. package/src/components/launcher/launcher.js +557 -0
  82. package/src/components/layout/layout.js +2 -2
  83. package/src/components/menu-button/menu-button.js +27 -2
  84. package/src/components/modal/modal.css +5 -1
  85. package/src/components/modal/modal.js +37 -2
  86. package/src/components/multi-value-editor/multi-value-editor.css +99 -15
  87. package/src/components/multi-value-editor/multi-value-editor.js +237 -19
  88. package/src/components/navigation-bar/navigation-bar.css +7 -0
  89. package/src/components/questionnaire/items.js +370 -0
  90. package/src/components/questionnaire/questionnaire.css +387 -0
  91. package/src/components/questionnaire/questionnaire.js +1033 -0
  92. package/src/components/search/search.css +10 -2
  93. package/src/components/select/select.css +6 -1
  94. package/src/components/select/select.js +99 -11
  95. package/src/components/sheet/sheet-stack.js +304 -0
  96. package/src/components/sheet/sheet.css +351 -0
  97. package/src/components/sheet/sheet.js +551 -0
  98. package/src/components/split-view/split-view.js +76 -161
  99. package/src/components/stepper/stepper.css +12 -2
  100. package/src/components/tabbox/tabbox.css +13 -3
  101. package/src/components/tabbox/tabbox.js +34 -10
  102. package/src/components/table/table.css +43 -0
  103. package/src/components/table/table.js +523 -45
  104. package/src/components/tooltip/tooltip.js +5 -2
  105. package/src/components/value-list/value-list.js +6 -3
  106. package/src/core/dom.js +302 -0
  107. package/src/core/drag-axis.js +203 -0
  108. package/src/core/position.js +68 -22
  109. package/src/index.js +19 -2
  110. package/styles/tokens/dark.css +15 -13
  111. package/styles/tokens/global.css +17 -5
  112. package/styles/tokens/semantic.css +14 -8
  113. package/styles/tokens/themes.css +72 -0
  114. package/styles/zx.css +11 -1
  115. package/dist/types/components/permission/permission.d.ts +0 -93
  116. package/src/components/permission/permission.css +0 -47
  117. package/src/components/permission/permission.js +0 -198
@@ -2,12 +2,15 @@
2
2
  import { clamp, uid } from './util.js';
3
3
 
4
4
  const PLACEMENTS = new Set([
5
- 'bottom-start', 'bottom-end', 'top-start', 'top-end', 'bottom', 'top'
5
+ 'bottom-start', 'bottom-end', 'top-start', 'top-end', 'bottom', 'top',
6
+ 'right-start', 'right-end', 'left-start', 'left-end', 'right', 'left'
6
7
  ]);
7
8
 
9
+ /** @typedef {'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'|'right-start'|'right-end'|'left-start'|'left-end'|'right'|'left'} Placement */
10
+
8
11
  /**
9
12
  * @typedef {Object} PositionOptions
10
- * @property {'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'} [placement='bottom-start']
13
+ * @property {'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'|'right-start'|'right-end'|'left-start'|'left-end'|'right'|'left'} [placement='bottom-start']
11
14
  * @property {number} [offset=4] Gap between anchor and floating element.
12
15
  * @property {boolean} [flip=true] Flip vertically when the preferred side overflows.
13
16
  * @property {boolean} [matchWidth=false] Set the floating element's minimum width to the anchor width.
@@ -50,13 +53,17 @@ export function position(anchor, floating, options = {}) {
50
53
  floating.style.inset = 'auto';
51
54
  floating.style.margin = '0';
52
55
  floating.style.setProperty('position-anchor', anchorName);
53
- floating.style.setProperty('position-area', positionArea(placement));
54
- floating.style.setProperty('inset-area', positionArea(placement));
56
+ const area = positionArea(placement, getComputedStyle(anchor).direction === 'rtl');
57
+ floating.style.setProperty('position-area', area);
58
+ floating.style.setProperty('inset-area', area);
55
59
  floating.style.setProperty(
56
60
  'position-try-fallbacks',
57
61
  flip ? 'flip-block, flip-inline, flip-block flip-inline' : 'none'
58
62
  );
59
- floating.style.setProperty(placement.startsWith('top') ? 'margin-block-end' : 'margin-block-start', `${offset}px`);
63
+ const margin = placement.startsWith('top') ? 'margin-bottom'
64
+ : placement.startsWith('bottom') ? 'margin-top'
65
+ : placement.startsWith('left') ? 'margin-right' : 'margin-left';
66
+ floating.style.setProperty(margin, `${offset}px`);
60
67
  update = () => {
61
68
  if (matchWidth) floating.style.minWidth = `${anchor.getBoundingClientRect().width}px`;
62
69
  };
@@ -104,15 +111,21 @@ export function position(anchor, floating, options = {}) {
104
111
  };
105
112
  }
106
113
 
107
- /** @param {string} placement @returns {string} */
108
- function positionArea(placement) {
114
+ /** @param {string} placement @param {boolean} rtl @returns {string} */
115
+ function positionArea(placement, rtl) {
109
116
  return {
110
- 'bottom-start': 'block-end span-inline-end',
111
- 'bottom-end': 'block-end span-inline-start',
112
- 'top-start': 'block-start span-inline-end',
113
- 'top-end': 'block-start span-inline-start',
114
- bottom: 'block-end',
115
- top: 'block-start'
117
+ 'bottom-start': rtl ? 'bottom span-left' : 'bottom span-right',
118
+ 'bottom-end': rtl ? 'bottom span-right' : 'bottom span-left',
119
+ 'top-start': rtl ? 'top span-left' : 'top span-right',
120
+ 'top-end': rtl ? 'top span-right' : 'top span-left',
121
+ 'right-start': 'right span-bottom',
122
+ 'right-end': 'right span-top',
123
+ 'left-start': 'left span-bottom',
124
+ 'left-end': 'left span-top',
125
+ bottom: 'bottom',
126
+ top: 'top',
127
+ right: 'right',
128
+ left: 'left'
116
129
  }[placement];
117
130
  }
118
131
 
@@ -129,27 +142,60 @@ function updateFallback(anchor, floating, { placement, offset, flip, matchWidth
129
142
  const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
130
143
  const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
131
144
  let actualPlacement = placement;
132
- const prefersBottom = placement.startsWith('bottom');
145
+ const side = placementSide(placement);
133
146
  const bottomY = anchorRect.bottom + offset;
134
147
  const topY = anchorRect.top - offset - floatingRect.height;
148
+ const rightX = anchorRect.right + offset;
149
+ const leftX = anchorRect.left - offset - floatingRect.width;
135
150
 
136
151
  if (flip) {
137
- if (prefersBottom && bottomY + floatingRect.height > viewportHeight && topY >= 0) {
138
- actualPlacement = /** @type {typeof placement} */ (placement.replace('bottom', 'top'));
139
- } else if (!prefersBottom && topY < 0 && bottomY + floatingRect.height <= viewportHeight) {
140
- actualPlacement = /** @type {typeof placement} */ (placement.replace('top', 'bottom'));
152
+ if (side === 'bottom' && bottomY + floatingRect.height > viewportHeight && topY >= 0) {
153
+ actualPlacement = flipPlacement(placement, 'bottom', 'top');
154
+ } else if (side === 'top' && topY < 0 && bottomY + floatingRect.height <= viewportHeight) {
155
+ actualPlacement = flipPlacement(placement, 'top', 'bottom');
156
+ } else if (side === 'right' && rightX + floatingRect.width > viewportWidth && leftX >= 0) {
157
+ actualPlacement = flipPlacement(placement, 'right', 'left');
158
+ } else if (side === 'left' && leftX < 0 && rightX + floatingRect.width <= viewportWidth) {
159
+ actualPlacement = flipPlacement(placement, 'left', 'right');
141
160
  }
142
161
  }
143
162
 
163
+ const actualSide = placementSide(actualPlacement);
144
164
  let left;
145
- if (actualPlacement.endsWith('-end')) left = anchorRect.right - floatingRect.width;
146
- else if (actualPlacement.endsWith('-start')) left = anchorRect.left;
147
- else left = anchorRect.left + (anchorRect.width - floatingRect.width) / 2;
148
- const top = actualPlacement.startsWith('bottom') ? bottomY : topY;
165
+ let top;
166
+ if (actualSide === 'bottom' || actualSide === 'top') {
167
+ const rtl = getComputedStyle(anchor).direction === 'rtl';
168
+ if (actualPlacement.endsWith('-end')) {
169
+ left = rtl ? anchorRect.left : anchorRect.right - floatingRect.width;
170
+ } else if (actualPlacement.endsWith('-start')) {
171
+ left = rtl ? anchorRect.right - floatingRect.width : anchorRect.left;
172
+ } else left = anchorRect.left + (anchorRect.width - floatingRect.width) / 2;
173
+ top = actualSide === 'bottom' ? bottomY : topY;
174
+ } else {
175
+ left = actualSide === 'right' ? rightX : leftX;
176
+ if (actualPlacement.endsWith('-end')) top = anchorRect.bottom - floatingRect.height;
177
+ else if (actualPlacement.endsWith('-start')) top = anchorRect.top;
178
+ else top = anchorRect.top + (anchorRect.height - floatingRect.height) / 2;
179
+ }
149
180
  floating.style.left = `${Math.round(clamp(left, 0, Math.max(0, viewportWidth - floatingRect.width)))}px`;
150
181
  floating.style.top = `${Math.round(clamp(top, 0, Math.max(0, viewportHeight - floatingRect.height)))}px`;
151
182
  }
152
183
 
184
+ /** @param {string} placement @returns {'top'|'bottom'|'left'|'right'} */
185
+ function placementSide(placement) {
186
+ return /** @type {'top'|'bottom'|'left'|'right'} */ (placement.split('-')[0]);
187
+ }
188
+
189
+ /**
190
+ * @param {string} placement
191
+ * @param {'top'|'bottom'|'left'|'right'} from
192
+ * @param {'top'|'bottom'|'left'|'right'} to
193
+ * @returns {Placement}
194
+ */
195
+ function flipPlacement(placement, from, to) {
196
+ return /** @type {Placement} */ (placement.replace(from, to));
197
+ }
198
+
153
199
  /** @param {HTMLElement} element @returns {void} */
154
200
  function showPopover(element) {
155
201
  if (typeof element.showPopover !== 'function') return;
package/src/index.js CHANGED
@@ -42,7 +42,12 @@ export function registerFieldAdapters() {
42
42
  registerFieldAdapters();
43
43
 
44
44
  export { Component } from './core/component.js';
45
- export { h, htmlEscape, resolveElement, highlightMatch } from './core/dom.js';
45
+ export {
46
+ h, htmlEscape, resolveElement, highlightMatch,
47
+ __, compactElement, fragment, parseCompactTag, applyCompactProperties,
48
+ appendContent, appendCompact, appendCompactChild,
49
+ onCompactEvent, offCompactEvent, fireCompactEvent
50
+ } from './core/dom.js';
46
51
  export { position } from './core/position.js';
47
52
  export { breakpoints, breakpointOf, matchBreakpoint, onBreakpoint } from './core/breakpoint.js';
48
53
  export { Http, zeyosService, parseResult } from './core/http.js';
@@ -88,15 +93,23 @@ export { MasterPanel } from './components/master-panel/master-panel.js';
88
93
  export {
89
94
  SplitView, clampSize, resolveSize, snapSize
90
95
  } from './components/split-view/split-view.js';
96
+ export { Dock } from './components/dock/dock.js';
91
97
  export { Tabbox } from './components/tabbox/tabbox.js';
92
98
  export { NavigationBar } from './components/navigation-bar/navigation-bar.js';
93
99
  export { Stepper } from './components/stepper/stepper.js';
94
100
  export { Breadcrumb } from './components/breadcrumb/breadcrumb.js';
95
101
  export { Pagination, paginationRange } from './components/pagination/pagination.js';
96
102
  export { Search } from './components/search/search.js';
103
+ export { Launcher, rankLauncherItems } from './components/launcher/launcher.js';
104
+ export { Avatar, avatarInitials } from './components/avatar/avatar.js';
105
+ export { AccountMenu } from './components/account-menu/account-menu.js';
106
+ export { AppRail, normalizeAppItems } from './components/app-rail/app-rail.js';
107
+ export { AppSidebar } from './components/app-sidebar/app-sidebar.js';
97
108
  export { Message } from './components/message/message.js';
98
109
  export { Modal } from './components/modal/modal.js';
99
110
  export { Dialog } from './components/dialog/dialog.js';
111
+ export { Sheet } from './components/sheet/sheet.js';
112
+ export { SheetStack } from './components/sheet/sheet-stack.js';
100
113
  export { Dropdown } from './components/dropdown/dropdown.js';
101
114
  export { Tooltip, tooltip, describe } from './components/tooltip/tooltip.js';
102
115
  export { MenuButton } from './components/menu-button/menu-button.js';
@@ -107,7 +120,6 @@ export { TagPicker } from './components/tag-picker/tag-picker.js';
107
120
  export { NumberField, parseNumber, snapNumber } from './components/number-field/number-field.js';
108
121
  export { Rating } from './components/rating/rating.js';
109
122
  export { Slider, stepPrecision } from './components/slider/slider.js';
110
- export { Permission } from './components/permission/permission.js';
111
123
  export { DatePicker } from './components/date-picker/date-picker.js';
112
124
  export { MonthPicker } from './components/date-picker/month-picker.js';
113
125
  export { TimePicker } from './components/date-picker/time-picker.js';
@@ -120,12 +132,17 @@ export {
120
132
  } from './components/datebox/date-range-box.js';
121
133
  export { Timebox, splitTime, joinTime } from './components/timebox/timebox.js';
122
134
  export { Table } from './components/table/table.js';
135
+ export { Grid, billingColumns, isBillingLine } from './components/grid/grid.js';
136
+ export {
137
+ Chart, ChartJsAdapter, chartSummaryTable, cloneChartValue, isEmptyChartData
138
+ } from './components/chart/chart.js';
123
139
  export { TreeView } from './components/tree/tree.js';
124
140
  export { Finder } from './components/finder/finder.js';
125
141
  export { DataFilter } from './components/data-filter/data-filter.js';
126
142
  export { Field } from './components/field/field.js';
127
143
  export { Fieldset } from './components/fieldset/fieldset.js';
128
144
  export { Form } from './components/form/form.js';
145
+ export { Questionnaire } from './components/questionnaire/questionnaire.js';
129
146
  export { ValueList } from './components/value-list/value-list.js';
130
147
  export { MultiValueEditor } from './components/multi-value-editor/multi-value-editor.js';
131
148
  export { FieldUpload } from './components/field-upload/field-upload.js';
@@ -1,7 +1,9 @@
1
1
  /*
2
- * Tier-2 semantic tokens — dark theme, from the shadcn/ui preset `b2BVl11e4` (Zinc):
3
- * Zinc-950 page, Zinc-900 cards and popovers, Zinc-800 muted fills, translucent white borders
4
- * (10%) and inputs (15%), Zinc-400 muted text.
2
+ * Tier-2 semantic tokens — dark theme: a near-black page, raised neutral surfaces, muted fills,
3
+ * translucent white borders (10%) and inputs (15%), and restrained secondary text.
4
+ *
5
+ * The accent roles take the light end of the `--zx-accent-*` ramp (300/400/500) where the light
6
+ * theme takes the dark end, so a preset that repoints the ramp lands correctly in both.
5
7
  *
6
8
  * The `[data-zx-theme="auto"]` block below repeats these assignments under a
7
9
  * `prefers-color-scheme` query; CSS has no way to share a declaration block across a media
@@ -15,7 +17,7 @@
15
17
  --zx-color-bg-control: color-mix(in srgb, var(--zx-gray-0) 5%, transparent);
16
18
  --zx-color-bg-muted: var(--zx-gray-800);
17
19
  --zx-color-bg-hover: color-mix(in srgb, var(--zx-gray-0) 8%, transparent);
18
- --zx-color-bg-selected: color-mix(in srgb, var(--zx-green-400) 18%, var(--zx-gray-900));
20
+ --zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-400) 18%, var(--zx-gray-900));
19
21
  --zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 75%, transparent);
20
22
  --zx-color-border: color-mix(in srgb, var(--zx-gray-0) 10%, transparent);
21
23
  --zx-color-border-strong: color-mix(in srgb, var(--zx-gray-0) 28%, transparent);
@@ -24,10 +26,10 @@
24
26
  --zx-color-text-muted: var(--zx-gray-400);
25
27
  --zx-color-text-placeholder: var(--zx-gray-500);
26
28
  --zx-color-text-invert: var(--zx-gray-950);
27
- --zx-color-accent: var(--zx-green-400);
28
- --zx-color-accent-hover: var(--zx-green-300);
29
- --zx-color-accent-active: var(--zx-green-500);
30
- --zx-color-accent-subtle: color-mix(in srgb, var(--zx-green-400) 16%, var(--zx-gray-900));
29
+ --zx-color-accent: var(--zx-accent-400);
30
+ --zx-color-accent-hover: var(--zx-accent-300);
31
+ --zx-color-accent-active: var(--zx-accent-500);
32
+ --zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-400) 16%, var(--zx-gray-900));
31
33
  --zx-color-on-accent: var(--zx-gray-950);
32
34
  --zx-color-danger: var(--zx-red-400);
33
35
  --zx-color-danger-bg: color-mix(in srgb, var(--zx-red-400) 16%, var(--zx-gray-900));
@@ -53,7 +55,7 @@
53
55
  --zx-color-bg-control: color-mix(in srgb, var(--zx-gray-0) 5%, transparent);
54
56
  --zx-color-bg-muted: var(--zx-gray-800);
55
57
  --zx-color-bg-hover: color-mix(in srgb, var(--zx-gray-0) 8%, transparent);
56
- --zx-color-bg-selected: color-mix(in srgb, var(--zx-green-400) 18%, var(--zx-gray-900));
58
+ --zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-400) 18%, var(--zx-gray-900));
57
59
  --zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 75%, transparent);
58
60
  --zx-color-border: color-mix(in srgb, var(--zx-gray-0) 10%, transparent);
59
61
  --zx-color-border-strong: color-mix(in srgb, var(--zx-gray-0) 28%, transparent);
@@ -62,10 +64,10 @@
62
64
  --zx-color-text-muted: var(--zx-gray-400);
63
65
  --zx-color-text-placeholder: var(--zx-gray-500);
64
66
  --zx-color-text-invert: var(--zx-gray-950);
65
- --zx-color-accent: var(--zx-green-400);
66
- --zx-color-accent-hover: var(--zx-green-300);
67
- --zx-color-accent-active: var(--zx-green-500);
68
- --zx-color-accent-subtle: color-mix(in srgb, var(--zx-green-400) 16%, var(--zx-gray-900));
67
+ --zx-color-accent: var(--zx-accent-400);
68
+ --zx-color-accent-hover: var(--zx-accent-300);
69
+ --zx-color-accent-active: var(--zx-accent-500);
70
+ --zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-400) 16%, var(--zx-gray-900));
69
71
  --zx-color-on-accent: var(--zx-gray-950);
70
72
  --zx-color-danger: var(--zx-red-400);
71
73
  --zx-color-danger-bg: color-mix(in srgb, var(--zx-red-400) 16%, var(--zx-gray-900));
@@ -1,9 +1,9 @@
1
1
  /*
2
2
  * Tier-1 palette and primitives.
3
3
  *
4
- * Derived from the shadcn/ui preset `b2BVl11e4` (style Nova · base colour Zinc · theme Zinc ·
5
- * chart colour Emerald · Inter · radius small). The neutral ramp is Tailwind Zinc; the accent
6
- * ramp is the preset's Emerald chart ramp, anchored at 400 to the ZeyOS brand green #21cc75.
4
+ * The neutral ramp uses Zinc-like values; the accent ramp uses an emerald progression anchored at
5
+ * 400 to the ZeyOS brand green #21cc75. Inter and a compact radius scale support dense business
6
+ * interfaces without coupling the token contract to another UI toolkit.
7
7
  *
8
8
  * Only tier-2 semantic tokens (tokens/semantic.css, tokens/dark.css) may reference these.
9
9
  * Component CSS must never use them directly — tests/lint-tokens.js enforces that.
@@ -24,13 +24,25 @@
24
24
  --zx-gray-900: #18181b;
25
25
  --zx-gray-950: #09090b;
26
26
 
27
- /* Accent — the preset's Emerald chart ramp, with the ZeyOS brand green at 400 */
27
+ /* Accent — an emerald ramp with the ZeyOS brand green at 400 */
28
28
  --zx-green-300: #5ee9b5;
29
29
  --zx-green-400: #21cc75;
30
30
  --zx-green-500: #009966;
31
31
  --zx-green-600: #007a55;
32
32
  --zx-green-700: #006045;
33
33
 
34
+ /*
35
+ * Accent ramp — the indirection the semantic tier reads. It defaults to the Emerald ramp
36
+ * above, which is what makes a theme preset five declarations rather than a second copy of
37
+ * every semantic mapping: `tokens/themes.css` repoints these, and light, dark, and auto all
38
+ * follow because each of them picks its own stop off the ramp.
39
+ */
40
+ --zx-accent-300: var(--zx-green-300);
41
+ --zx-accent-400: var(--zx-green-400);
42
+ --zx-accent-500: var(--zx-green-500);
43
+ --zx-accent-600: var(--zx-green-600);
44
+ --zx-accent-700: var(--zx-green-700);
45
+
34
46
  /* Status */
35
47
  --zx-red-400: #ff6467;
36
48
  --zx-red-500: #e7000b;
@@ -51,7 +63,7 @@
51
63
  --zx-space-7: 32px;
52
64
  --zx-space-8: 40px;
53
65
 
54
- /* Radius — the preset's `--radius: 0.45rem`, with shadcn's derived steps */
66
+ /* Radius — a 0.45rem base with compact derived steps */
55
67
  --zx-radius: 0.45rem;
56
68
  --zx-radius-sm: calc(var(--zx-radius) - 4px);
57
69
  --zx-radius-md: calc(var(--zx-radius) - 2px);
@@ -1,9 +1,13 @@
1
1
  /*
2
2
  * Tier-2 semantic tokens — light theme (the default).
3
3
  *
4
- * The mapping follows the shadcn/ui preset `b2BVl11e4`: white surfaces, Zinc-100 hover/muted
5
- * fills, Zinc-200 borders and inputs, Zinc-500 muted text, Zinc-950 body text, and the Nova
6
- * control geometry (32px controls, `--radius` corners, a 3px translucent focus ring).
4
+ * The mapping uses white surfaces, restrained neutral hover/muted fills, quiet borders and inputs,
5
+ * strong body text, and compact control geometry (32px controls, `--radius` corners, a 3px
6
+ * translucent focus ring).
7
+ *
8
+ * The accent roles read `--zx-accent-*` rather than the green ramp directly, which is what lets
9
+ * `tokens/themes.css` retheme them. Status colours keep their own ramps on purpose — see the note
10
+ * in that file.
7
11
  */
8
12
  :root,
9
13
  [data-zx-theme="light"] {
@@ -14,7 +18,7 @@
14
18
  --zx-color-bg-control: var(--zx-gray-0);
15
19
  --zx-color-bg-muted: var(--zx-gray-100);
16
20
  --zx-color-bg-hover: var(--zx-gray-100);
17
- --zx-color-bg-selected: color-mix(in srgb, var(--zx-green-600) 10%, var(--zx-gray-0));
21
+ --zx-color-bg-selected: color-mix(in srgb, var(--zx-accent-600) 10%, var(--zx-gray-0));
18
22
  --zx-color-bg-backdrop: color-mix(in srgb, var(--zx-gray-950) 50%, transparent);
19
23
  --zx-color-border: var(--zx-gray-200);
20
24
  --zx-color-border-strong: var(--zx-gray-300);
@@ -23,10 +27,10 @@
23
27
  --zx-color-text-muted: var(--zx-gray-500);
24
28
  --zx-color-text-placeholder: var(--zx-gray-400);
25
29
  --zx-color-text-invert: var(--zx-gray-50);
26
- --zx-color-accent: var(--zx-green-600);
27
- --zx-color-accent-hover: var(--zx-green-700);
28
- --zx-color-accent-active: var(--zx-green-700);
29
- --zx-color-accent-subtle: color-mix(in srgb, var(--zx-green-600) 10%, var(--zx-gray-0));
30
+ --zx-color-accent: var(--zx-accent-600);
31
+ --zx-color-accent-hover: var(--zx-accent-700);
32
+ --zx-color-accent-active: var(--zx-accent-700);
33
+ --zx-color-accent-subtle: color-mix(in srgb, var(--zx-accent-600) 10%, var(--zx-gray-0));
30
34
  --zx-color-on-accent: var(--zx-gray-0);
31
35
  --zx-color-danger: var(--zx-red-500);
32
36
  --zx-color-danger-bg: color-mix(in srgb, var(--zx-red-500) 10%, var(--zx-gray-0));
@@ -44,6 +48,8 @@
44
48
  --zx-control-font-size: var(--zx-text-md);
45
49
  --zx-control-font-weight: 500;
46
50
  --zx-overlay-shadow: var(--zx-shadow-3);
51
+ /* Blur applied behind a backdrop that asked for it. Theme-independent, so light defines it once. */
52
+ --zx-overlay-blur: 8px;
47
53
  --zx-header-bg: var(--zx-gray-900);
48
54
  --zx-header-text: var(--zx-gray-50);
49
55
  }
@@ -0,0 +1,72 @@
1
+ /*
2
+ * Standard theme presets.
3
+ *
4
+ * A preset repoints the tier-1 accent ramp — nothing else. The semantic tier picks its own stop
5
+ * off that ramp per polarity (600/700 on light surfaces, 300/400/500 on dark ones), so five
6
+ * declarations retheme light, dark, and auto at once, and every component follows without a
7
+ * second mapping to keep in sync.
8
+ *
9
+ * Set the preset alongside the theme: `<html data-zx-theme="dark" data-zx-preset="ocean">`.
10
+ * `zx` is the default and never needs stating; the attribute exists so an application can pin it.
11
+ *
12
+ * Status colours are deliberately not part of a preset. Danger, warning, and success mean the
13
+ * same thing whatever a product's brand colour is, and a preset that repainted them would leave
14
+ * an application with no reliable way to say "this failed".
15
+ *
16
+ * Every 600 clears 4.5:1 against white and against the light page, and every 400 clears it
17
+ * against the dark page, which is what keeps `--zx-color-on-accent` correct in both polarities.
18
+ */
19
+
20
+ /* Zx — the ZeyOS brand green on Xenon's emerald ramp. The default. */
21
+ [data-zx-preset="zx"] {
22
+ --zx-accent-300: #5ee9b5;
23
+ --zx-accent-400: #21cc75;
24
+ --zx-accent-500: #009966;
25
+ --zx-accent-600: #007a55;
26
+ --zx-accent-700: #006045;
27
+ }
28
+
29
+ /* ZeyOS — the gold of the ZeyOS product marque, anchored at 400. */
30
+ [data-zx-preset="zeyos"] {
31
+ --zx-accent-300: #ffd9a8;
32
+ --zx-accent-400: #f7bc60;
33
+ --zx-accent-500: #d0952f;
34
+ --zx-accent-600: #96690f;
35
+ --zx-accent-700: #6f4e0b;
36
+ }
37
+
38
+ /* Ocean — the palette's own blue ramp, for products that read as utilities rather than brands. */
39
+ [data-zx-preset="ocean"] {
40
+ --zx-accent-300: #8ec5ff;
41
+ --zx-accent-400: #51a2ff;
42
+ --zx-accent-500: #2b7fff;
43
+ --zx-accent-600: #155dfc;
44
+ --zx-accent-700: #1447e6;
45
+ }
46
+
47
+ /* Violet */
48
+ [data-zx-preset="violet"] {
49
+ --zx-accent-300: #c4b4ff;
50
+ --zx-accent-400: #a684ff;
51
+ --zx-accent-500: #8e51ff;
52
+ --zx-accent-600: #7f22fe;
53
+ --zx-accent-700: #7008e7;
54
+ }
55
+
56
+ /* Rose */
57
+ [data-zx-preset="rose"] {
58
+ --zx-accent-300: #ffa1ad;
59
+ --zx-accent-400: #ff637e;
60
+ --zx-accent-500: #ff2056;
61
+ --zx-accent-600: #dc0039;
62
+ --zx-accent-700: #a80030;
63
+ }
64
+
65
+ /* Slate — a near-neutral accent, for screens where the data should carry the colour. */
66
+ [data-zx-preset="slate"] {
67
+ --zx-accent-300: #cad5e2;
68
+ --zx-accent-400: #90a1b9;
69
+ --zx-accent-500: #62748e;
70
+ --zx-accent-600: #45556c;
71
+ --zx-accent-700: #314158;
72
+ }
package/styles/zx.css CHANGED
@@ -1,4 +1,5 @@
1
1
  @import url("./tokens/global.css");
2
+ @import url("./tokens/themes.css");
2
3
  @import url("./tokens/semantic.css");
3
4
  @import url("./tokens/dark.css");
4
5
  @import url("./tokens/density.css");
@@ -25,12 +26,19 @@
25
26
  @import url("../src/components/tabbox/tabbox.css");
26
27
  @import url("../src/components/navigation-bar/navigation-bar.css");
27
28
  @import url("../src/components/search/search.css");
29
+ @import url("../src/components/launcher/launcher.css");
30
+ @import url("../src/components/avatar/avatar.css");
31
+ @import url("../src/components/account-menu/account-menu.css");
32
+ @import url("../src/components/app-rail/app-rail.css");
33
+ @import url("../src/components/app-sidebar/app-sidebar.css");
28
34
  @import url("../src/components/message/message.css");
29
35
  @import url("../src/components/modal/modal.css");
30
36
  @import url("../src/components/dialog/dialog.css");
37
+ @import url("../src/components/sheet/sheet.css");
31
38
  @import url("../src/components/dropdown/dropdown.css");
32
39
  @import url("../src/components/tooltip/tooltip.css");
33
40
  @import url("../src/components/split-view/split-view.css");
41
+ @import url("../src/components/dock/dock.css");
34
42
  @import url("../src/components/menu-button/menu-button.css");
35
43
  @import url("../src/components/context-menu/context-menu.css");
36
44
  @import url("../src/components/select/select.css");
@@ -39,7 +47,6 @@
39
47
  @import url("../src/components/number-field/number-field.css");
40
48
  @import url("../src/components/slider/slider.css");
41
49
  @import url("../src/components/rating/rating.css");
42
- @import url("../src/components/permission/permission.css");
43
50
  @import url("../src/components/date-picker/date-picker.css");
44
51
  @import url("../src/components/date-picker/time-picker.css");
45
52
  @import url("../src/components/datebox/datebox.css");
@@ -47,6 +54,8 @@
47
54
  @import url("../src/components/datebox/date-range-box.css");
48
55
  @import url("../src/components/timebox/timebox.css");
49
56
  @import url("../src/components/table/table.css");
57
+ @import url("../src/components/grid/grid.css");
58
+ @import url("../src/components/chart/chart.css");
50
59
  @import url("../src/components/tree/tree.css");
51
60
  @import url("../src/components/finder/finder.css");
52
61
  @import url("../src/components/data-filter/data-filter.css");
@@ -59,3 +68,4 @@
59
68
  @import url("../src/components/value-list/value-list.css");
60
69
  @import url("../src/components/multi-value-editor/multi-value-editor.css");
61
70
  @import url("../src/components/field-upload/field-upload.css");
71
+ @import url("../src/components/questionnaire/questionnaire.css");
@@ -1,93 +0,0 @@
1
- import { Component } from '../../core/component.js';
2
- import { Select } from '../select/select.js';
3
- export type PermissionGroup = Record<string, any> | string | number | boolean | symbol | bigint | null | undefined;
4
- export type PermissionOptions = {
5
- /**
6
- * Public, private, or group ID.
7
- */
8
- value?: boolean | string | number | symbol | bigint | null;
9
- /**
10
- * Available groups.
11
- */
12
- groups?: PermissionGroup[];
13
- /**
14
- * Group ID property or reader.
15
- */
16
- groupsValueKey?: string | ((item: PermissionGroup) => unknown);
17
- /**
18
- * Group label property or reader.
19
- */
20
- groupsLabelKey?: string | ((item: PermissionGroup) => string);
21
- /**
22
- * Localized messages.
23
- */
24
- msg?: Record<string, string> | Record<string, Record<string, string>>;
25
- /**
26
- * Change listener.
27
- */
28
- onchange?: (event: CustomEvent<PermissionChangeDetail>) => void;
29
- };
30
- export type PermissionChangeDetail = {
31
- value: unknown;
32
- };
33
- /** @typedef {Record<string, any>|string|number|boolean|symbol|bigint|null|undefined} PermissionGroup */
34
- /**
35
- * @typedef {Object} PermissionOptions
36
- * @property {boolean|string|number|symbol|bigint|null} [value=true] Public, private, or group ID.
37
- * @property {PermissionGroup[]} [groups=[]] Available groups.
38
- * @property {string|((item: PermissionGroup) => unknown)} [groupsValueKey='ID'] Group ID property or reader.
39
- * @property {string|((item: PermissionGroup) => string)} [groupsLabelKey='name'] Group label property or reader.
40
- * @property {Record<string, string>|Record<string, Record<string, string>>} [msg] Localized messages.
41
- * @property {(event: CustomEvent<PermissionChangeDetail>) => void} [onchange] Change listener.
42
- */
43
- /** @typedef {{value: unknown}} PermissionChangeDetail */
44
- /**
45
- * Record-permission choice for private, public, and group access.
46
- *
47
- * @fires Permission#change
48
- * @extends {Component<PermissionOptions>}
49
- */
50
- export declare class Permission extends Component<PermissionOptions> {
51
- _mode: string;
52
- _groupValue: any;
53
- _groupSelect: Select;
54
- _createdRoot: boolean;
55
- _originalChildren: any[] | ChildNode[];
56
- _root: HTMLElement;
57
- _originalState: string;
58
- static cssName: string;
59
- /** @type {PermissionOptions} */
60
- static defaults: PermissionOptions;
61
- /** @returns {HTMLElement} */
62
- render(): HTMLElement;
63
- /** Returns the normalized permission value. @returns {'private'|'public'|unknown} */
64
- get(): 'private' | 'public' | unknown;
65
- /**
66
- * Sets a public, private, or group permission.
67
- * @param {boolean|string|number|symbol|bigint|null} value Permission value.
68
- * @param {{silent?: boolean}} [options={}] Update behavior.
69
- * @returns {this}
70
- * @fires Permission#change
71
- */
72
- set(value: boolean | string | number | symbol | bigint | null, { silent }?: {
73
- silent?: boolean;
74
- }): this;
75
- /** Destroys the embedded Select and restores an enhanced target. @returns {void} */
76
- destroy(): void;
77
- /** @returns {void} */
78
- _selectGroupMode(): void;
79
- /** @returns {void} */
80
- _sync(): void;
81
- /**
82
- * @param {string} name
83
- * @param {'private'|'public'|'group'} value
84
- * @param {string} text
85
- * @returns {{label: HTMLLabelElement, input: HTMLInputElement}}
86
- */
87
- _choice(name: string, value: 'private' | 'public' | 'group', text: string): {
88
- label: HTMLLabelElement;
89
- input: HTMLInputElement;
90
- };
91
- /** @param {string} key @param {string} fallback @returns {string} */
92
- _message(key: string, fallback: string): string;
93
- }
@@ -1,47 +0,0 @@
1
- .zx-permission {
2
- min-inline-size: 0;
3
- color: var(--zx-color-text);
4
- font-size: var(--zx-control-font-size);
5
- }
6
-
7
- .zx-permission__choices {
8
- display: grid;
9
- grid-template-columns: repeat(3, max-content) minmax(160px, 1fr);
10
- align-items: center;
11
- gap: var(--zx-space-2) var(--zx-space-4);
12
- }
13
-
14
- .zx-permission__choice {
15
- display: inline-flex;
16
- align-items: center;
17
- gap: var(--zx-space-2);
18
- min-block-size: var(--zx-control-height);
19
- cursor: pointer;
20
- }
21
-
22
- .zx-permission__choice input {
23
- accent-color: var(--zx-color-accent);
24
- }
25
-
26
- .zx-permission__choice:has(input:focus-visible) {
27
- border-radius: var(--zx-radius-sm);
28
- box-shadow: var(--zx-focus-ring);
29
- }
30
-
31
- .zx-permission__groups {
32
- min-inline-size: 160px;
33
- }
34
-
35
- .zx-permission:not([data-state="group"]) .zx-permission__groups {
36
- color: var(--zx-color-text-muted);
37
- }
38
-
39
- @media (max-width: 640px) {
40
- .zx-permission__choices {
41
- grid-template-columns: 1fr;
42
- }
43
-
44
- .zx-permission__groups {
45
- inline-size: 100%;
46
- }
47
- }