@apliteni/apliteni-ui 0.11.4 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.11.4",
3
+ "version": "0.12.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
@@ -6,7 +6,29 @@
6
6
  //
7
7
  // Each value is the INNER markup; icon() wraps it in the shared <svg>. Glyphs
8
8
  // are grouped by domain — the flat ICONS map is what icon() looks up, and
9
- // iconCategories drives the Storybook grid. Add a glyph to the right group.
9
+ // iconCategories drives the Storybook grid.
10
+ //
11
+ // ---- Adding a glyph -------------------------------------------------------
12
+ //
13
+ // NAME it for what it depicts, not for the one place it is used: `trash`, not
14
+ // `deleteWorkspace`. camelCase, and a modifier follows its noun — `circleX`,
15
+ // `eyeOff`, `trendingUp` — so the family sorts together. A name is taken once;
16
+ // a second declaration of one is a gate failure, not a merge conflict.
17
+ //
18
+ // GROUP it by what it depicts, again rather than by caller. `chart` lives in
19
+ // DATA because it draws data, even when a comms panel is what renders it. If
20
+ // two groups both look right, the glyph belongs to the one whose other members
21
+ // it would sit beside in the catalogue. Groups are not tags: exactly one.
22
+ //
23
+ // PROVENANCE: the path comes from Lucide, unmodified, at the 24×24 / 1.7 house
24
+ // stroke — that is what keeps the set looking like one hand. Say which Lucide
25
+ // name it came from in the commit if the two differ. A hand-drawn path needs a
26
+ // reason in the commit message, because the next person cannot tell one from a
27
+ // traced one by looking.
28
+ //
29
+ // The gates: src/assets/icons.test.js holds one-group-per-glyph and the
30
+ // emitter's numbers, and stories/guidelines/iconography.test.js holds the
31
+ // icon-only list below. The written rules are on Guidelines / Iconography.
10
32
 
11
33
  const NAV = {
12
34
  chevronDown: '<path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/>',
@@ -101,9 +123,6 @@ const COMMS = {
101
123
  logout: '<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/>',
102
124
  plug: '<path d="M12 22v-5"/><path d="M15 8V2"/><path d="M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z"/><path d="M9 8V2"/>',
103
125
  sparkle: '<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',
104
- card: '<rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/>',
105
- doc: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/>',
106
- chart: '<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>',
107
126
  };
108
127
 
109
128
  const BRAND = {
@@ -140,5 +159,49 @@ export const icon = (name, cls = '') =>
140
159
 
141
160
  export const iconNames = Object.keys(ICONS);
142
161
 
162
+ // Which controls may be an icon and nothing else — a closed list, not a
163
+ // judgement call in review.
164
+ //
165
+ // The accessibility half was already held: every glyph is aria-hidden, so
166
+ // button({ iconOnly }) names itself from `label`. That says a nameless icon
167
+ // button cannot ship; it never said when a wordless one SHOULD. This does.
168
+ //
169
+ // A control whose action is on this list may drop its visible text. Everything
170
+ // else carries a label — including glyphs that feel obvious in isolation, like
171
+ // `gear` or `externalLink`, because a reader meets them one at a time and a
172
+ // toolbar is not a legend. Adding an entry is a decision recorded here, which
173
+ // is the point: the alternative rules read well and could not be gated.
174
+ export const iconOnlyAllowed = {
175
+ x: 'close or dismiss',
176
+ copy: 'copy to clipboard',
177
+ moreHorizontal: 'overflow menu',
178
+ moreVertical: 'overflow menu',
179
+ chevronDown: 'expand or collapse',
180
+ chevronUp: 'expand or collapse',
181
+ };
182
+
183
+ // What a glyph means when a component picks it for the reader rather than a
184
+ // caller naming it. Two rules hold the map together:
185
+ //
186
+ // a CIRCLED glyph is a state the system is in — circleCheck, circleX,
187
+ // circleAlert. It is reported to you and you cannot click it.
188
+ // a BARE glyph is an action you can take — x dismisses, check confirms,
189
+ // trash deletes.
190
+ //
191
+ // That split is what a danger toast needed: it used to render the same bare `x`
192
+ // twice, once meaning "this failed" and once meaning "make this go away". The
193
+ // bare x is now reserved for the close button, and status took the circle
194
+ // family the kit was already shipping and never using.
195
+ export const iconMeanings = {
196
+ circleCheck: 'a state: it succeeded',
197
+ circleX: 'a state: it failed',
198
+ circleAlert: 'a state: it needs attention',
199
+ info: 'a state: something worth knowing, no action required',
200
+ bolt: 'a state: it happened, with no verdict attached',
201
+ x: 'an action: close or dismiss this',
202
+ check: 'an action: confirm this',
203
+ trash: 'an action: delete this',
204
+ };
205
+
143
206
  export const sun = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>';
144
207
  export const moon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>';
@@ -16,6 +16,10 @@ export const esc = (s) => String(s == null ? '' : s).replace(/[&<>"]/g, (c) => (
16
16
  // stops being decoration and becomes the control's ONLY accessible name. It is
17
17
  // mirrored into aria-label + title, and an empty label falls back to the icon
18
18
  // name rather than shipping a nameless button.
19
+ //
20
+ // That is the accessibility half, and it is not permission. WHEN a control may
21
+ // go wordless is a closed list — `iconOnlyAllowed` in src/assets/icons.js — and
22
+ // stories/guidelines/iconography.test.js reviews call sites against it.
19
23
  export function button({
20
24
  label = 'Button', variant = 'secondary', size = 'md', icon: ic, iconSvg, iconRight,
21
25
  block = false, disabled = false, busy = false, type = 'button', href, iconOnly = false,
@@ -217,8 +221,18 @@ export function switchToggle({ checked = false, disabled = false, name, label =
217
221
  export function callout({ variant, icon: ic = 'info', body } = {}) {
218
222
  return `<div class="${cx('ui-callout', variant && `ui-callout--${variant}`)}"><span class="ui-callout__icon">${icon(ic)}</span><div>${body}</div></div>`;
219
223
  }
220
- // Default icon per status — overridable with `icon`.
221
- const TOAST_ICON = { success: 'check', danger: 'x', warn: 'alert', info: 'info', neutral: 'bolt' };
224
+ // Default icon per status — overridable with `icon`. The circle family is not
225
+ // decoration: a circled glyph is a STATE the system reports, a bare one is an
226
+ // ACTION you can take (iconMeanings in src/assets/icons.js).
227
+ //
228
+ // This used to read `success: 'check', danger: 'x', warn: 'alert'`, which made
229
+ // a danger toast render the same bare `x` twice — once as the status, meaning
230
+ // "this failed", once as the close button, meaning "make this go away". Status
231
+ // took the circle glyphs the kit already shipped and never used, and the bare
232
+ // `x` now belongs to the close button alone.
233
+ const TOAST_ICON = {
234
+ success: 'circleCheck', danger: 'circleX', warn: 'circleAlert', info: 'info', neutral: 'bolt',
235
+ };
222
236
  // A toast carries a status (colour) and a style (surface). Everything visual is
223
237
  // token-driven: the status modifier sets --toast-accent/-glow/-on, the style
224
238
  // modifier consumes them. `action` adds a trailing button ("Undo"/"Retry"),