@ttoss/fsl-ui 0.2.4

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 (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +30 -0
  4. package/dist/components/Breadcrumbs/Breadcrumbs.cjs +129 -0
  5. package/dist/components/Breadcrumbs/Breadcrumbs.d.cts +61 -0
  6. package/dist/components/Breadcrumbs/Breadcrumbs.d.mts +61 -0
  7. package/dist/components/Breadcrumbs/Breadcrumbs.mjs +126 -0
  8. package/dist/components/Button/Button.cjs +80 -0
  9. package/dist/components/Button/Button.d.cts +68 -0
  10. package/dist/components/Button/Button.d.mts +68 -0
  11. package/dist/components/Button/Button.mjs +79 -0
  12. package/dist/components/Checkbox/Checkbox.cjs +183 -0
  13. package/dist/components/Checkbox/Checkbox.d.cts +45 -0
  14. package/dist/components/Checkbox/Checkbox.d.mts +45 -0
  15. package/dist/components/Checkbox/Checkbox.mjs +182 -0
  16. package/dist/components/CheckboxGroup/CheckboxGroup.cjs +97 -0
  17. package/dist/components/CheckboxGroup/CheckboxGroup.d.cts +56 -0
  18. package/dist/components/CheckboxGroup/CheckboxGroup.d.mts +56 -0
  19. package/dist/components/CheckboxGroup/CheckboxGroup.mjs +96 -0
  20. package/dist/components/FileTrigger/FileTrigger.cjs +51 -0
  21. package/dist/components/FileTrigger/FileTrigger.d.cts +52 -0
  22. package/dist/components/FileTrigger/FileTrigger.d.mts +52 -0
  23. package/dist/components/FileTrigger/FileTrigger.mjs +50 -0
  24. package/dist/components/GridList/GridList.cjs +220 -0
  25. package/dist/components/GridList/GridList.d.cts +72 -0
  26. package/dist/components/GridList/GridList.d.mts +72 -0
  27. package/dist/components/GridList/GridList.mjs +217 -0
  28. package/dist/components/Group/Group.cjs +77 -0
  29. package/dist/components/Group/Group.d.cts +61 -0
  30. package/dist/components/Group/Group.d.mts +61 -0
  31. package/dist/components/Group/Group.mjs +74 -0
  32. package/dist/components/Icon/Icon.cjs +52 -0
  33. package/dist/components/Icon/Icon.mjs +52 -0
  34. package/dist/components/Icon/glyphs.cjs +72 -0
  35. package/dist/components/Icon/glyphs.mjs +63 -0
  36. package/dist/components/Link/Link.cjs +62 -0
  37. package/dist/components/Link/Link.d.cts +38 -0
  38. package/dist/components/Link/Link.d.mts +38 -0
  39. package/dist/components/Link/Link.mjs +61 -0
  40. package/dist/components/ListBox/ListBox.cjs +126 -0
  41. package/dist/components/ListBox/ListBox.d.cts +63 -0
  42. package/dist/components/ListBox/ListBox.d.mts +63 -0
  43. package/dist/components/ListBox/ListBox.mjs +123 -0
  44. package/dist/components/Meter/Meter.cjs +126 -0
  45. package/dist/components/Meter/Meter.d.cts +63 -0
  46. package/dist/components/Meter/Meter.d.mts +63 -0
  47. package/dist/components/Meter/Meter.mjs +125 -0
  48. package/dist/components/NumberField/NumberField.cjs +221 -0
  49. package/dist/components/NumberField/NumberField.d.cts +68 -0
  50. package/dist/components/NumberField/NumberField.d.mts +68 -0
  51. package/dist/components/NumberField/NumberField.mjs +220 -0
  52. package/dist/components/ProgressBar/ProgressBar.cjs +132 -0
  53. package/dist/components/ProgressBar/ProgressBar.d.cts +56 -0
  54. package/dist/components/ProgressBar/ProgressBar.d.mts +56 -0
  55. package/dist/components/ProgressBar/ProgressBar.mjs +129 -0
  56. package/dist/components/RadioGroup/RadioGroup.cjs +218 -0
  57. package/dist/components/RadioGroup/RadioGroup.d.cts +82 -0
  58. package/dist/components/RadioGroup/RadioGroup.d.mts +82 -0
  59. package/dist/components/RadioGroup/RadioGroup.mjs +215 -0
  60. package/dist/components/Select/Select.cjs +253 -0
  61. package/dist/components/Select/Select.d.cts +86 -0
  62. package/dist/components/Select/Select.d.mts +86 -0
  63. package/dist/components/Select/Select.mjs +250 -0
  64. package/dist/components/Separator/Separator.cjs +64 -0
  65. package/dist/components/Separator/Separator.d.cts +44 -0
  66. package/dist/components/Separator/Separator.d.mts +44 -0
  67. package/dist/components/Separator/Separator.mjs +63 -0
  68. package/dist/components/Slider/Slider.cjs +160 -0
  69. package/dist/components/Slider/Slider.d.cts +45 -0
  70. package/dist/components/Slider/Slider.d.mts +45 -0
  71. package/dist/components/Slider/Slider.mjs +159 -0
  72. package/dist/components/Switch/Switch.cjs +176 -0
  73. package/dist/components/Switch/Switch.d.cts +43 -0
  74. package/dist/components/Switch/Switch.d.mts +43 -0
  75. package/dist/components/Switch/Switch.mjs +175 -0
  76. package/dist/components/Tabs/Tabs.cjs +180 -0
  77. package/dist/components/Tabs/Tabs.d.cts +85 -0
  78. package/dist/components/Tabs/Tabs.d.mts +85 -0
  79. package/dist/components/Tabs/Tabs.mjs +173 -0
  80. package/dist/components/Toast/Toast.cjs +218 -0
  81. package/dist/components/Toast/Toast.d.cts +96 -0
  82. package/dist/components/Toast/Toast.d.mts +96 -0
  83. package/dist/components/Toast/Toast.mjs +214 -0
  84. package/dist/components/ToggleButton/ToggleButton.cjs +125 -0
  85. package/dist/components/ToggleButton/ToggleButton.d.cts +43 -0
  86. package/dist/components/ToggleButton/ToggleButton.d.mts +43 -0
  87. package/dist/components/ToggleButton/ToggleButton.mjs +124 -0
  88. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.cjs +48 -0
  89. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.cts +41 -0
  90. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.mts +41 -0
  91. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.mjs +47 -0
  92. package/dist/components/Toolbar/Toolbar.cjs +67 -0
  93. package/dist/components/Toolbar/Toolbar.d.cts +60 -0
  94. package/dist/components/Toolbar/Toolbar.d.mts +60 -0
  95. package/dist/components/Toolbar/Toolbar.mjs +66 -0
  96. package/dist/composites/Accordion/Accordion.cjs +279 -0
  97. package/dist/composites/Accordion/Accordion.d.cts +176 -0
  98. package/dist/composites/Accordion/Accordion.d.mts +176 -0
  99. package/dist/composites/Accordion/Accordion.mjs +270 -0
  100. package/dist/composites/ConfirmationDialog/ConfirmationDialog.cjs +206 -0
  101. package/dist/composites/ConfirmationDialog/ConfirmationDialog.d.cts +166 -0
  102. package/dist/composites/ConfirmationDialog/ConfirmationDialog.d.mts +166 -0
  103. package/dist/composites/ConfirmationDialog/ConfirmationDialog.mjs +203 -0
  104. package/dist/composites/Dialog/Dialog.cjs +372 -0
  105. package/dist/composites/Dialog/Dialog.d.cts +234 -0
  106. package/dist/composites/Dialog/Dialog.d.mts +234 -0
  107. package/dist/composites/Dialog/Dialog.mjs +360 -0
  108. package/dist/composites/Disclosure/Disclosure.cjs +214 -0
  109. package/dist/composites/Disclosure/Disclosure.d.cts +118 -0
  110. package/dist/composites/Disclosure/Disclosure.d.mts +118 -0
  111. package/dist/composites/Disclosure/Disclosure.mjs +207 -0
  112. package/dist/composites/Form/Form.cjs +161 -0
  113. package/dist/composites/Form/Form.d.cts +176 -0
  114. package/dist/composites/Form/Form.d.mts +176 -0
  115. package/dist/composites/Form/Form.mjs +156 -0
  116. package/dist/composites/Menu/Menu.cjs +190 -0
  117. package/dist/composites/Menu/Menu.d.cts +158 -0
  118. package/dist/composites/Menu/Menu.d.mts +158 -0
  119. package/dist/composites/Menu/Menu.mjs +186 -0
  120. package/dist/composites/Popover/Popover.cjs +80 -0
  121. package/dist/composites/Popover/Popover.d.cts +56 -0
  122. package/dist/composites/Popover/Popover.d.mts +56 -0
  123. package/dist/composites/Popover/Popover.mjs +78 -0
  124. package/dist/composites/SearchField/SearchField.cjs +194 -0
  125. package/dist/composites/SearchField/SearchField.d.cts +81 -0
  126. package/dist/composites/SearchField/SearchField.d.mts +81 -0
  127. package/dist/composites/SearchField/SearchField.mjs +189 -0
  128. package/dist/composites/TagGroup/TagGroup.cjs +212 -0
  129. package/dist/composites/TagGroup/TagGroup.d.cts +84 -0
  130. package/dist/composites/TagGroup/TagGroup.d.mts +84 -0
  131. package/dist/composites/TagGroup/TagGroup.mjs +209 -0
  132. package/dist/composites/TextArea/TextArea.cjs +190 -0
  133. package/dist/composites/TextArea/TextArea.d.cts +95 -0
  134. package/dist/composites/TextArea/TextArea.d.mts +95 -0
  135. package/dist/composites/TextArea/TextArea.mjs +181 -0
  136. package/dist/composites/TextField/TextField.cjs +200 -0
  137. package/dist/composites/TextField/TextField.d.cts +111 -0
  138. package/dist/composites/TextField/TextField.d.mts +111 -0
  139. package/dist/composites/TextField/TextField.mjs +191 -0
  140. package/dist/composites/Tooltip/Tooltip.cjs +79 -0
  141. package/dist/composites/Tooltip/Tooltip.d.cts +53 -0
  142. package/dist/composites/Tooltip/Tooltip.d.mts +53 -0
  143. package/dist/composites/Tooltip/Tooltip.mjs +77 -0
  144. package/dist/composites/Wizard/Wizard.cjs +333 -0
  145. package/dist/composites/Wizard/Wizard.d.cts +206 -0
  146. package/dist/composites/Wizard/Wizard.d.mts +206 -0
  147. package/dist/composites/Wizard/Wizard.mjs +324 -0
  148. package/dist/composites/scope.cjs +124 -0
  149. package/dist/composites/scope.mjs +121 -0
  150. package/dist/index.cjs +186 -0
  151. package/dist/index.d.cts +37 -0
  152. package/dist/index.d.mts +37 -0
  153. package/dist/index.mjs +39 -0
  154. package/dist/semantics/componentMeta.d.cts +37 -0
  155. package/dist/semantics/componentMeta.d.mts +37 -0
  156. package/dist/semantics/index.cjs +16 -0
  157. package/dist/semantics/index.d.cts +4 -0
  158. package/dist/semantics/index.d.mts +4 -0
  159. package/dist/semantics/index.mjs +3 -0
  160. package/dist/semantics/taxonomy.cjs +150 -0
  161. package/dist/semantics/taxonomy.d.cts +153 -0
  162. package/dist/semantics/taxonomy.d.mts +153 -0
  163. package/dist/semantics/taxonomy.mjs +140 -0
  164. package/dist/tokens/escapeHatch.cjs +13 -0
  165. package/dist/tokens/escapeHatch.mjs +13 -0
  166. package/dist/tokens/focusRing.cjs +28 -0
  167. package/dist/tokens/focusRing.mjs +28 -0
  168. package/dist/tokens/keyframes.cjs +76 -0
  169. package/dist/tokens/keyframes.mjs +75 -0
  170. package/dist/tokens/resolveInteractiveStyle.cjs +41 -0
  171. package/dist/tokens/resolveInteractiveStyle.mjs +41 -0
  172. package/llms.txt +142 -0
  173. package/package.json +70 -0
  174. package/src/tokens/CONTRACT.md +505 -0
@@ -0,0 +1,28 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import { vars } from "@ttoss/fsl-theme/vars";
3
+
4
+ //#region src/tokens/focusRing.ts
5
+ /**
6
+ * Focus ring resolver — the cross-cutting keyboard-focus outline every
7
+ * interactive component applies per `CONTRACT.md §3`:
8
+ *
9
+ * - always via `outline` (never `border`) so focus cannot layout-shift;
10
+ * - always from the cross-cutting `vars.focus.ring.*` tokens (CONTRACT §1
11
+ * cross-cutting table), never from per-entity color subtrees.
12
+ *
13
+ * Companion to `resolveInteractiveStyle`: that helper owns the state
14
+ * cascade for color dimensions; this one owns the single state-dependent
15
+ * outline. Both exist so components never re-implement state ternaries
16
+ * (structural tokens like radii/spacing stay literal reads by design).
17
+ */
18
+ /**
19
+ * Returns the `outline` CSS value for the current focus-visible state.
20
+ * Pair with `outlineOffset` at the call site when the component floats the
21
+ * ring off its edge.
22
+ */
23
+ var focusRingOutline = isFocusVisible => {
24
+ return isFocusVisible ? `${vars.focus.ring.width} ${vars.focus.ring.style} ${vars.focus.ring.color}` : "none";
25
+ };
26
+
27
+ //#endregion
28
+ export { focusRingOutline };
@@ -0,0 +1,76 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ //#region src/tokens/keyframes.ts
3
+ /**
4
+ * Runtime `@keyframes` registry for `@ttoss/fsl-ui`.
5
+ *
6
+ * Components style themselves exclusively through inline styles (no CSS
7
+ * files ship with the package), but CSS animations can only reference
8
+ * `@keyframes` declared in a real stylesheet. This module owns that
9
+ * stylesheet: a single `<style id="fsl-ui-keyframes">` element injected
10
+ * once per document, SSR-safe and idempotent.
11
+ *
12
+ * Rules (enforced by `tests/unit/tests/keyframes.test.ts` and the contract
13
+ * suite):
14
+ *
15
+ * 1. Every animation name used by a component MUST be registered in
16
+ * `ANIMATION_NAMES` — components reference `ANIMATION_NAMES.*`, never a
17
+ * bare string.
18
+ * 2. Every registered name MUST have a matching `@keyframes` block in
19
+ * `KEYFRAMES_CSS`.
20
+ * 3. The stylesheet disables all registered animations under
21
+ * `prefers-reduced-motion: reduce`.
22
+ */
23
+ var STYLE_ELEMENT_ID = "fsl-ui-keyframes";
24
+ /**
25
+ * Canonical animation names shipped by the package. Components must
26
+ * reference these constants (never string literals) so the contract test
27
+ * can prove every `animation:` in `src/` resolves to a real `@keyframes`.
28
+ */
29
+ var ANIMATION_NAMES = {
30
+ /** Indeterminate ProgressBar fill sweep. */
31
+ progressBarIndeterminate: "tt-progressbar-indeterminate"
32
+ };
33
+ /**
34
+ * The full stylesheet injected by {@link ensureKeyframes}. Uses logical
35
+ * properties only (`margin-inline-start`) so the sweep direction follows
36
+ * the writing direction under `dir="rtl"`.
37
+ */
38
+ var KEYFRAMES_CSS = `
39
+ @keyframes ${ANIMATION_NAMES.progressBarIndeterminate} {
40
+ 0% { margin-inline-start: -40%; }
41
+ 100% { margin-inline-start: 100%; }
42
+ }
43
+ @media (prefers-reduced-motion: reduce) {
44
+ [data-scope] [data-part] { animation: none !important; }
45
+ }
46
+ `.trim();
47
+ var injected = false;
48
+ /**
49
+ * Injects the package stylesheet into `document.head` exactly once.
50
+ * No-op on the server (SSR-safe) and when the element already exists
51
+ * (e.g. two copies of the package on one page).
52
+ *
53
+ * Call it from a `React.useInsertionEffect` in any component that uses a
54
+ * name from {@link ANIMATION_NAMES} — insertion effects never run during
55
+ * server rendering, so the SSR guard below is defense in depth for direct
56
+ * callers, not the primary mechanism.
57
+ */
58
+ var ensureKeyframes = () => {
59
+ if (injected) return;
60
+ const doc = globalThis.document;
61
+ /* istanbul ignore next -- SSR guard: jsdom always provides a document */
62
+ if (doc === void 0) return;
63
+ if (doc.getElementById(STYLE_ELEMENT_ID) !== null) {
64
+ injected = true;
65
+ return;
66
+ }
67
+ const style = doc.createElement("style");
68
+ style.id = STYLE_ELEMENT_ID;
69
+ style.textContent = KEYFRAMES_CSS;
70
+ doc.head.appendChild(style);
71
+ injected = true;
72
+ };
73
+
74
+ //#endregion
75
+ exports.ANIMATION_NAMES = ANIMATION_NAMES;
76
+ exports.ensureKeyframes = ensureKeyframes;
@@ -0,0 +1,75 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ //#region src/tokens/keyframes.ts
3
+ /**
4
+ * Runtime `@keyframes` registry for `@ttoss/fsl-ui`.
5
+ *
6
+ * Components style themselves exclusively through inline styles (no CSS
7
+ * files ship with the package), but CSS animations can only reference
8
+ * `@keyframes` declared in a real stylesheet. This module owns that
9
+ * stylesheet: a single `<style id="fsl-ui-keyframes">` element injected
10
+ * once per document, SSR-safe and idempotent.
11
+ *
12
+ * Rules (enforced by `tests/unit/tests/keyframes.test.ts` and the contract
13
+ * suite):
14
+ *
15
+ * 1. Every animation name used by a component MUST be registered in
16
+ * `ANIMATION_NAMES` — components reference `ANIMATION_NAMES.*`, never a
17
+ * bare string.
18
+ * 2. Every registered name MUST have a matching `@keyframes` block in
19
+ * `KEYFRAMES_CSS`.
20
+ * 3. The stylesheet disables all registered animations under
21
+ * `prefers-reduced-motion: reduce`.
22
+ */
23
+ var STYLE_ELEMENT_ID = "fsl-ui-keyframes";
24
+ /**
25
+ * Canonical animation names shipped by the package. Components must
26
+ * reference these constants (never string literals) so the contract test
27
+ * can prove every `animation:` in `src/` resolves to a real `@keyframes`.
28
+ */
29
+ var ANIMATION_NAMES = {
30
+ /** Indeterminate ProgressBar fill sweep. */
31
+ progressBarIndeterminate: "tt-progressbar-indeterminate"
32
+ };
33
+ /**
34
+ * The full stylesheet injected by {@link ensureKeyframes}. Uses logical
35
+ * properties only (`margin-inline-start`) so the sweep direction follows
36
+ * the writing direction under `dir="rtl"`.
37
+ */
38
+ var KEYFRAMES_CSS = `
39
+ @keyframes ${ANIMATION_NAMES.progressBarIndeterminate} {
40
+ 0% { margin-inline-start: -40%; }
41
+ 100% { margin-inline-start: 100%; }
42
+ }
43
+ @media (prefers-reduced-motion: reduce) {
44
+ [data-scope] [data-part] { animation: none !important; }
45
+ }
46
+ `.trim();
47
+ var injected = false;
48
+ /**
49
+ * Injects the package stylesheet into `document.head` exactly once.
50
+ * No-op on the server (SSR-safe) and when the element already exists
51
+ * (e.g. two copies of the package on one page).
52
+ *
53
+ * Call it from a `React.useInsertionEffect` in any component that uses a
54
+ * name from {@link ANIMATION_NAMES} — insertion effects never run during
55
+ * server rendering, so the SSR guard below is defense in depth for direct
56
+ * callers, not the primary mechanism.
57
+ */
58
+ var ensureKeyframes = () => {
59
+ if (injected) return;
60
+ const doc = globalThis.document;
61
+ /* istanbul ignore next -- SSR guard: jsdom always provides a document */
62
+ if (doc === void 0) return;
63
+ if (doc.getElementById(STYLE_ELEMENT_ID) !== null) {
64
+ injected = true;
65
+ return;
66
+ }
67
+ const style = doc.createElement("style");
68
+ style.id = STYLE_ELEMENT_ID;
69
+ style.textContent = KEYFRAMES_CSS;
70
+ doc.head.appendChild(style);
71
+ injected = true;
72
+ };
73
+
74
+ //#endregion
75
+ export { ANIMATION_NAMES, ensureKeyframes };
@@ -0,0 +1,41 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ const require_taxonomy = require('../semantics/taxonomy.cjs');
3
+
4
+ //#region src/tokens/resolveInteractiveStyle.ts
5
+ /**
6
+ * Resolves a single style value from a semantic interactive state object
7
+ * using the canonical cascade defined by `STATE_PRIORITY` in
8
+ * `../semantics/taxonomy`.
9
+ *
10
+ * `STATE_PRIORITY` is the single source of truth for both the **order** of
11
+ * the cascade and the **flag → state-key** mapping. `CONTRACT.md §3`
12
+ * references it by name; this helper iterates it. Order and mapping cannot
13
+ * drift between the contract doc and the implementation because they are
14
+ * derived from the same tuple.
15
+ *
16
+ * The helper is **strict**: when a flag is set, the corresponding state's
17
+ * value is returned as-is (even when `undefined`). Two authoring knobs keep
18
+ * component call sites expressive without re-introducing the copy-pasted
19
+ * ternary chain:
20
+ *
21
+ * - **Omit irrelevant flags** from `flags` to skip that level entirely —
22
+ * e.g. drop `isFocusVisible` for `background`/`text` dimensions that
23
+ * never change on focus.
24
+ * - **Apply `?? states.default` at the call site** when fallback to the
25
+ * resting state is desired (e.g. Button text, where `action.*.text.active`
26
+ * and `action.*.text.hover` are not always defined on every evaluation).
27
+ *
28
+ * Consumed by `Button`, `Link`, `Checkbox`, `Switch`, `RadioGroup`, `Select`,
29
+ * `TextField`, and `Accordion`.
30
+ */
31
+ var resolveInteractiveStyle = (states, flags) => {
32
+ if (!states) return void 0;
33
+ for (const {
34
+ flag,
35
+ state
36
+ } of require_taxonomy.STATE_PRIORITY) if (flags[flag]) return states[state];
37
+ return states.default;
38
+ };
39
+
40
+ //#endregion
41
+ exports.resolveInteractiveStyle = resolveInteractiveStyle;
@@ -0,0 +1,41 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import { STATE_PRIORITY } from "../semantics/taxonomy.mjs";
3
+
4
+ //#region src/tokens/resolveInteractiveStyle.ts
5
+ /**
6
+ * Resolves a single style value from a semantic interactive state object
7
+ * using the canonical cascade defined by `STATE_PRIORITY` in
8
+ * `../semantics/taxonomy`.
9
+ *
10
+ * `STATE_PRIORITY` is the single source of truth for both the **order** of
11
+ * the cascade and the **flag → state-key** mapping. `CONTRACT.md §3`
12
+ * references it by name; this helper iterates it. Order and mapping cannot
13
+ * drift between the contract doc and the implementation because they are
14
+ * derived from the same tuple.
15
+ *
16
+ * The helper is **strict**: when a flag is set, the corresponding state's
17
+ * value is returned as-is (even when `undefined`). Two authoring knobs keep
18
+ * component call sites expressive without re-introducing the copy-pasted
19
+ * ternary chain:
20
+ *
21
+ * - **Omit irrelevant flags** from `flags` to skip that level entirely —
22
+ * e.g. drop `isFocusVisible` for `background`/`text` dimensions that
23
+ * never change on focus.
24
+ * - **Apply `?? states.default` at the call site** when fallback to the
25
+ * resting state is desired (e.g. Button text, where `action.*.text.active`
26
+ * and `action.*.text.hover` are not always defined on every evaluation).
27
+ *
28
+ * Consumed by `Button`, `Link`, `Checkbox`, `Switch`, `RadioGroup`, `Select`,
29
+ * `TextField`, and `Accordion`.
30
+ */
31
+ var resolveInteractiveStyle = (states, flags) => {
32
+ if (!states) return void 0;
33
+ for (const {
34
+ flag,
35
+ state
36
+ } of STATE_PRIORITY) if (flags[flag]) return states[state];
37
+ return states.default;
38
+ };
39
+
40
+ //#endregion
41
+ export { resolveInteractiveStyle };
package/llms.txt ADDED
@@ -0,0 +1,142 @@
1
+ # @ttoss/fsl-ui
2
+
3
+ Semantic, token-native React component library. Built on React Aria
4
+ Components; styled exclusively with `@ttoss/fsl-theme` CSS-variable tokens.
5
+ Every component declares a formal semantic identity (FSL — Foundational
6
+ Semantic Language) that determines which tokens it may consume.
7
+
8
+ Ground truth in the published package: `src/tokens/CONTRACT.md` (full Layer-2
9
+ contract). This file is the distilled, machine-oriented summary.
10
+
11
+ ## Setup
12
+
13
+ ```tsx
14
+ import { createTheme } from '@ttoss/fsl-theme';
15
+ import { ThemeProvider } from '@ttoss/fsl-theme/react';
16
+ import { Button } from '@ttoss/fsl-ui';
17
+
18
+ const theme = createTheme(); // base theme + dark alternate
19
+
20
+ <ThemeProvider theme={theme} defaultMode="system">
21
+ <Button evaluation="primary" onPress={save}>Save</Button>
22
+ </ThemeProvider>
23
+ ```
24
+
25
+ Without a ThemeProvider (or ThemeHead/ThemeScript on SSR) the CSS variables
26
+ are undefined and components render unstyled.
27
+
28
+ ## Semantic model (what the props mean)
29
+
30
+ - entity — what the component IS (fixed per component, not a prop):
31
+ Action, Input, Selection, Navigation, Disclosure, Overlay, Feedback,
32
+ Collection, Structure.
33
+ - evaluation (prop) — AUTHORIAL emphasis, chosen when writing the UI:
34
+ e.g. 'primary' | 'secondary' | 'accent' | 'muted' | 'negative' on Action.
35
+ Input/Selection components have NO evaluation prop (data entry carries no
36
+ authorial voice); validation is the runtime `invalid` STATE (`isInvalid`),
37
+ never `evaluation="negative"`.
38
+ - consequence (prop) — effect on state: 'neutral' | 'committing' |
39
+ 'destructive'. Drives MECHANISM (e.g. ConfirmationDialog two-click arming),
40
+ not color. Destructive ≠ negative color; pair them explicitly if desired.
41
+ - composition (prop on leaves) — slot the element plays inside a parent:
42
+ 'primaryAction' | 'secondaryAction' | 'dismissAction' … DialogActions
43
+ reorders children by it per platform convention.
44
+ - State — runtime only (hover, active, focused, disabled, checked,
45
+ indeterminate, expanded, invalid, …). Emitted by React Aria render props;
46
+ priority cascade: disabled > invalid > expanded > indeterminate >
47
+ selected > focusVisible > pressed > hovered > default.
48
+
49
+ ## Component catalog (all exports also ship a `*Meta` identity object)
50
+
51
+ Action: Button, ToggleButton, FileTrigger (opens OS file picker),
52
+ MenuItem (inside Menu), FormSubmit (inside Form)
53
+ Navigation: Link, Breadcrumbs/Breadcrumb, Tabs/TabList/Tab
54
+ (TabPanel is Structure — the content revealed by the tabs)
55
+ Disclosure: Accordion, AccordionItem, AccordionTrigger, AccordionPanel,
56
+ Disclosure, DisclosureTrigger, DisclosurePanel (standalone single
57
+ section — Accordion is the DisclosureGroup)
58
+ Selection: Checkbox, CheckboxGroup, RadioGroup/Radio, Switch,
59
+ Select/SelectItem, ToggleButtonGroup, TagGroup/Tag
60
+ (CheckboxGroup group-level isInvalid propagates to child Checkboxes;
61
+ its label part is Selection/label, but description + validationMessage
62
+ are internal parts — Selection has no such structural roles.
63
+ TagGroup/Tag: a chosen tag uses the `selected` State, NOT `pressed`
64
+ — a tag is set membership, not a toggle; remove button is an
65
+ internal closeTrigger part (not a Selection role))
66
+ Collection: ListBox/ListBoxItem, GridList/GridListItem (+ Menu/MenuItem,
67
+ listed under Overlay for its popover surface). ADR-007: the
68
+ CONTAINER is Collection (informational surface) but selectable
69
+ ITEMS are Selection (input chrome, `selected` State) — one
70
+ composite, two entities. GridListItem also has a selectionControl
71
+ (per-row checkbox).
72
+ Input: TextField, TextArea (each + Label/Control/Description/Error),
73
+ SearchField (+ Label/Control; leading search + clear glyphs),
74
+ NumberField (label/description/errorMessage props + −/+ steppers),
75
+ Slider (label + value output; single value or [min,max] range)
76
+ Overlay: Dialog, DialogModal, DialogTrigger, DialogHeading, DialogBody,
77
+ DialogActions, Menu, MenuTrigger, ConfirmationDialog,
78
+ Popover, PopoverTrigger, Tooltip, TooltipTrigger
79
+ Feedback: ProgressBar, Meter, Toast, ToastRegion, createToastQueue
80
+ (Meter = static quantity in a range e.g. battery/disk;
81
+ ProgressBar = a task in flight. Pick by "state" vs "progressing")
82
+ Structure: Form, FormActions, Wizard, WizardStep, WizardSummary,
83
+ WizardNavigation, Separator, Group (labelled role=group frame),
84
+ Toolbar (role=toolbar, arrow-key roving nav over its controls)
85
+
86
+ Icons: INTERNAL only (not exported). Components render glyphs through an
87
+ internal semantic Icon layer (`src/components/Icon/`) that maps `icon.{family}.{intent}`
88
+ intents to Lucide glyphs via the Iconify provider (`@iconify-icon/react`),
89
+ registered offline (no runtime API fetch). Future standalone `@ttoss/fsl-icon`.
90
+ See CONTRIBUTING ADR-005.
91
+
92
+ ## Entity → token map (a component reads ONLY its row)
93
+
94
+ Action → colors.action, radii.control, motion.feedback
95
+ Input → colors.input, radii.control, motion.feedback
96
+ Selection → colors.input, radii.control, motion.feedback
97
+ Navigation → colors.navigation, radii.control, motion.feedback
98
+ Disclosure → colors.navigation, radii.control, motion.transition
99
+ Overlay → colors.informational, radii.surface, motion.transition, elevation.overlay
100
+ Feedback → colors.feedback, radii.surface, elevation.raised
101
+ Collection → colors.informational, radii.surface
102
+ Structure → colors.informational, radii.surface
103
+
104
+ Color path formula: `vars.colors.{ux}[evaluation][background|border|text][state]`
105
+ → CSS var `--tt-colors-{ux}-{evaluation}-{dimension}-{state}`.
106
+
107
+ ## Rules an integrating agent must follow
108
+
109
+ 1. Composites accept NO `style`/`className`. Customize geometry via CSS
110
+ custom-property knobs on the composite scope (fallbacks built in):
111
+ `--fsl-dialog-max-width` (default min(500px, 90vw)),
112
+ `--fsl-dialog-max-height` (90vh), `--fsl-menu-min-width` (12rem),
113
+ `--fsl-menu-max-width` (min(320px, 90vw)),
114
+ `--fsl-popover-max-width` (min(320px, 90vw)),
115
+ `--fsl-tooltip-max-width` (min(280px, 90vw)).
116
+ Example: `[data-scope='dialog'] { --fsl-dialog-max-width: 720px; }`
117
+ 2. There is NO `size` prop anywhere. Different density = different
118
+ semantic identity = different component.
119
+ 3. i18n: flow-critical labels are REQUIRED props with no defaults —
120
+ ConfirmationDialog (confirmLabel, cancelLabel, armedLabel when
121
+ consequence="destructive") and WizardNavigation (prevLabel, nextLabel,
122
+ finishLabel). Supply localized copy from the host app.
123
+ 4. Validation: pass `isInvalid` (or React Aria `validate`) — never a color
124
+ prop. Invalid styling comes from `input.*.{dimension}.invalid` tokens.
125
+ 5. Destructive confirms: `<ConfirmationDialog consequence="destructive">`
126
+ requires TWO clicks (arming). `consequence="committing"` +
127
+ `evaluation="negative"` gives a red one-click confirm.
128
+ 6. Every element exposes `data-scope`/`data-part` (plus `data-evaluation`,
129
+ `data-consequence`, `data-composition`, `data-arming` where relevant) —
130
+ use these for CSS targeting and tests; never rely on internal class names.
131
+ 7. All layout is logical-property based (RTL-safe); keep host CSS logical too.
132
+
133
+ ## Package facts
134
+
135
+ - ESM only, `sideEffects: false`, tree-shakes (Button-only import ≈ 1.8 KB
136
+ min before deps). Peer deps: react >= 18, react-dom >= 18.
137
+ - `react-aria-components` pinned `~1.19.0` while Toast uses UNSTABLE_ APIs.
138
+ - SSR-safe: the only DOM injection (`@keyframes` for ProgressBar) happens in
139
+ a client-only insertion effect. Icon glyphs register into an in-memory
140
+ Iconify registry (no DOM, no network), so they are SSR-safe too.
141
+ - Icons: Iconify (`@iconify-icon/react`) is the official glyph provider;
142
+ default set is Lucide (`@iconify/icons-lucide`, per-icon / tree-shakeable).
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@ttoss/fsl-ui",
3
+ "version": "0.2.4",
4
+ "description": "Semantic, token-native component library for the ttoss ecosystem. Built on React Aria Components with @ttoss/fsl-theme tokens.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/ttoss/ttoss.git",
8
+ "directory": "packages/fsl-ui"
9
+ },
10
+ "license": "MIT",
11
+ "author": "Ennio Lopes <enniolopes@gmail.com>",
12
+ "sideEffects": false,
13
+ "type": "module",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.mts",
17
+ "module": "./dist/index.mjs",
18
+ "browser": "./dist/index.mjs",
19
+ "import": "./dist/index.mjs",
20
+ "default": "./dist/index.mjs"
21
+ },
22
+ "./semantics": {
23
+ "types": "./dist/semantics/index.d.mts",
24
+ "default": "./dist/semantics/index.mjs"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "llms.txt",
30
+ "src/tokens/CONTRACT.md"
31
+ ],
32
+ "dependencies": {
33
+ "@iconify-icon/react": "^2.2.0",
34
+ "@iconify/icons-lucide": "^1.2.135",
35
+ "react-aria-components": "~1.19.0",
36
+ "@ttoss/fsl-theme": "^2.1.1"
37
+ },
38
+ "devDependencies": {
39
+ "@testing-library/react": "^16.3.2",
40
+ "@testing-library/user-event": "^14.6.1",
41
+ "@types/jest-axe": "^3.5.9",
42
+ "@types/node": "^24.12.0",
43
+ "@types/react": "^19.2.14",
44
+ "@types/react-dom": "^19.0.2",
45
+ "esbuild": "^0.28.0",
46
+ "jest": "^30.4.2",
47
+ "jest-axe": "^10.0.0",
48
+ "react": "^19.2.6",
49
+ "react-dom": "^19.2.6",
50
+ "react-hook-form": "^7.71.1",
51
+ "tsdown": "^0.22.2",
52
+ "zod": "^4.4.3",
53
+ "@ttoss/test-utils": "^4.2.18",
54
+ "@ttoss/config": "^1.37.17",
55
+ "@ttoss/forms": "^0.44.4"
56
+ },
57
+ "peerDependencies": {
58
+ "react": ">=18",
59
+ "react-dom": ">=18"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public",
63
+ "provenance": true
64
+ },
65
+ "scripts": {
66
+ "build": "tsdown",
67
+ "test": "tsc --noEmit -p tsconfig.json && jest --projects tests/unit",
68
+ "verify:treeshake": "node scripts/verify-treeshake.mjs"
69
+ }
70
+ }