@effigy-analytics/morass 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kevin Blum
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Morass
2
+
3
+ Morass is a small React UI framework for durable product interfaces: app shells, dense dashboards, forms, modal workflows, and status-heavy operational views.
4
+
5
+ Morass is the standard UI package for the Effigy Analytics suite. It was born inside Webbery, but its public API is generic: primitives only, no product domain logic in the root export.
6
+
7
+ ## Status
8
+
9
+ - TypeScript React package, MIT licensed
10
+ - Vite library build
11
+ - CSS token system
12
+ - Accessible primitives for shell, cards, controls, tabs, modals, progress, and status
13
+ - CI-ready lint, typecheck, test, and build scripts
14
+
15
+ ## Installation
16
+
17
+ The package is published to GitHub Packages under the `@effigy-analytics` scope. GitHub Packages requires authentication to install, even for public packages — consumers need an `.npmrc` pointing the scope at the registry and a token with `read:packages`:
18
+
19
+ ```
20
+ @effigy-analytics:registry=https://npm.pkg.github.com
21
+ ```
22
+
23
+ ```bash
24
+ npm install @effigy-analytics/morass
25
+ ```
26
+
27
+ ## Development
28
+
29
+ ```bash
30
+ npm install
31
+ npm run check
32
+ npm run build
33
+ ```
34
+
35
+ ## Public API
36
+
37
+ ```tsx
38
+ import { AppFrame, Button, Card, StatusPill } from "@effigy-analytics/morass";
39
+ import "@effigy-analytics/morass/styles.css";
40
+ ```
41
+
42
+ Primitives: `AppFrame`, `Button`, `Card`, `TextField`, `SelectField`, `StatusPill`, `Metric`, `Tabs`, `ProgressSteps`, `Modal`, plus shared tone/utility helpers.
43
+
44
+ Morass ships unopinionated class names and CSS variables. Applications can override tokens at `:root` or inside a scoped theme container.
45
+
46
+ ### Subpath: reminders
47
+
48
+ Due-date presentation helpers (`DueState`, `getDueStateTone`, `formatRelativeDue`) live behind a subpath export so the root API stays purely generic:
49
+
50
+ ```ts
51
+ import {
52
+ formatRelativeDue,
53
+ getDueStateTone,
54
+ } from "@effigy-analytics/morass/reminders";
55
+ ```
56
+
57
+ Moved out of the root export in 0.2.0.
58
+
59
+ ## Release Boundary
60
+
61
+ Morass is consumed by Effigy Analytics products (Webbery today, the platform apps as they adopt it) as a versioned package. Treat these surfaces as public within a published version:
62
+
63
+ - exports from `@effigy-analytics/morass`
64
+ - exports from `@effigy-analytics/morass/reminders`
65
+ - `@effigy-analytics/morass/styles.css`
66
+ - CSS custom properties intended for application theming
67
+ - component semantics and required peer dependency ranges
68
+
69
+ Breaking changes require a coordinated consumer update and a major version or explicit release note (pre-1.0, breaking changes ride minor versions and are called out in release notes). Consumers should pin Morass to a published version instead of depending on a live sibling checkout.
70
+
71
+ Before publishing:
72
+
73
+ ```bash
74
+ npm run check
75
+ ```
76
+
77
+ `npm run check` includes `npm pack --dry-run` after the library build, so CI
78
+ verifies the publishable package contents before a release. Then publish through
79
+ the GitHub Actions `Publish` workflow from a GitHub release whose tag matches
80
+ `v<package.json version>`.
81
+
82
+ ## License
83
+
84
+ [MIT](LICENSE)
@@ -0,0 +1,67 @@
1
+ import type { ButtonHTMLAttributes, HTMLAttributes, InputHTMLAttributes, LabelHTMLAttributes, ReactNode, SelectHTMLAttributes } from "react";
2
+ import { type Tone } from "./utils";
3
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
4
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
5
+ icon?: ReactNode;
6
+ variant?: ButtonVariant;
7
+ }
8
+ export declare function Button({ children, className, icon, type, variant, ...props }: ButtonProps): import("react").JSX.Element;
9
+ export interface CardProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
10
+ actions?: ReactNode;
11
+ eyebrow?: ReactNode;
12
+ title?: ReactNode;
13
+ }
14
+ export declare function Card({ actions, children, className, eyebrow, title, ...props }: CardProps): import("react").JSX.Element;
15
+ export interface AppFrameProps {
16
+ children: ReactNode;
17
+ header?: ReactNode;
18
+ nav?: ReactNode;
19
+ sidebar?: ReactNode;
20
+ }
21
+ export declare function AppFrame({ children, header, nav, sidebar }: AppFrameProps): import("react").JSX.Element;
22
+ export interface FieldProps {
23
+ error?: ReactNode;
24
+ helpText?: ReactNode;
25
+ label: ReactNode;
26
+ labelProps?: LabelHTMLAttributes<HTMLLabelElement>;
27
+ }
28
+ export interface TextFieldProps extends InputHTMLAttributes<HTMLInputElement>, FieldProps {
29
+ }
30
+ export declare function TextField({ error, helpText, label, labelProps, ...props }: TextFieldProps): import("react").JSX.Element;
31
+ export interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElement>, FieldProps {
32
+ }
33
+ export declare function SelectField({ children, error, helpText, label, labelProps, ...props }: SelectFieldProps): import("react").JSX.Element;
34
+ export interface StatusPillProps {
35
+ children: ReactNode;
36
+ tone?: Tone;
37
+ }
38
+ export declare function StatusPill({ children, tone }: StatusPillProps): import("react").JSX.Element;
39
+ export interface MetricProps {
40
+ label: ReactNode;
41
+ value: ReactNode;
42
+ }
43
+ export declare function Metric({ label, value }: MetricProps): import("react").JSX.Element;
44
+ export interface TabsProps<TValue extends string> {
45
+ "aria-label": string;
46
+ onValueChange: (value: TValue) => void;
47
+ tabs: Array<{
48
+ label: ReactNode;
49
+ value: TValue;
50
+ }>;
51
+ value: TValue;
52
+ }
53
+ export declare function Tabs<TValue extends string>({ "aria-label": ariaLabel, onValueChange, tabs, value, }: TabsProps<TValue>): import("react").JSX.Element;
54
+ export interface ProgressStepsProps {
55
+ current: number;
56
+ steps: string[];
57
+ }
58
+ export declare function ProgressSteps({ current, steps }: ProgressStepsProps): import("react").JSX.Element;
59
+ export interface ModalProps {
60
+ actions?: ReactNode;
61
+ children: ReactNode;
62
+ onClose: () => void;
63
+ open: boolean;
64
+ title: ReactNode;
65
+ }
66
+ export declare function Modal({ actions, children, onClose, open, title }: ModalProps): import("react").JSX.Element | null;
67
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import "./styles.css";
2
+ export * from "./components";
3
+ export * from "./utils";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react/jsx-runtime");function t(...e){return e.filter(Boolean).join(` `)}function n(e,t){return`${e} ${e}--${t}`}function r({children:n,className:r,icon:i,type:a=`button`,variant:o=`secondary`,...s}){return(0,e.jsxs)(`button`,{className:t(`m-button`,`m-button--${o}`,r),type:a,...s,children:[i?(0,e.jsx)(`span`,{className:`m-button__icon`,children:i}):null,n?(0,e.jsx)(`span`,{className:`m-button__label`,children:n}):null]})}function i({actions:n,children:r,className:i,eyebrow:a,title:o,...s}){return(0,e.jsxs)(`section`,{className:t(`m-card`,i),...s,children:[a||o||n?(0,e.jsxs)(`header`,{className:`m-card__header`,children:[(0,e.jsxs)(`div`,{children:[a?(0,e.jsx)(`p`,{className:`m-eyebrow`,children:a}):null,o?(0,e.jsx)(`h2`,{className:`m-card__title`,children:o}):null]}),n?(0,e.jsx)(`div`,{className:`m-card__actions`,children:n}):null]}):null,r?(0,e.jsx)(`div`,{className:`m-card__body`,children:r}):null]})}function a({children:t,header:n,nav:r,sidebar:i}){return(0,e.jsxs)(`div`,{className:`m-app-frame`,children:[i?(0,e.jsx)(`aside`,{className:`m-app-frame__sidebar`,children:i}):null,(0,e.jsxs)(`div`,{className:`m-app-frame__main`,children:[n?(0,e.jsx)(`header`,{className:`m-app-frame__header`,children:n}):null,(0,e.jsx)(`main`,{className:`m-app-frame__content`,children:t}),r?(0,e.jsx)(`nav`,{className:`m-app-frame__nav`,children:r}):null]})]})}function o({error:t,helpText:n,label:r,labelProps:i,...a}){return(0,e.jsxs)(`label`,{className:`m-field`,...i,children:[(0,e.jsx)(`span`,{className:`m-field__label`,children:r}),(0,e.jsx)(`input`,{className:`m-input`,...a}),n?(0,e.jsx)(`span`,{className:`m-field__help`,children:n}):null,t?(0,e.jsx)(`span`,{className:`m-field__error`,children:t}):null]})}function s({children:t,error:n,helpText:r,label:i,labelProps:a,...o}){return(0,e.jsxs)(`label`,{className:`m-field`,...a,children:[(0,e.jsx)(`span`,{className:`m-field__label`,children:i}),(0,e.jsx)(`select`,{className:`m-input m-input--select`,...o,children:t}),r?(0,e.jsx)(`span`,{className:`m-field__help`,children:r}):null,n?(0,e.jsx)(`span`,{className:`m-field__error`,children:n}):null]})}function c({children:t,tone:r=`neutral`}){return(0,e.jsx)(`span`,{className:n(`m-status-pill`,r),children:t})}function l({label:t,value:n}){return(0,e.jsxs)(`div`,{className:`m-metric`,children:[(0,e.jsx)(`dt`,{children:t}),(0,e.jsx)(`dd`,{children:n})]})}function u({"aria-label":n,onValueChange:r,tabs:i,value:a}){return(0,e.jsx)(`div`,{"aria-label":n,className:`m-tabs`,role:`tablist`,children:i.map(n=>(0,e.jsx)(`button`,{"aria-selected":n.value===a,className:t(`m-tabs__tab`,n.value===a&&`m-tabs__tab--active`),onClick:()=>r(n.value),role:`tab`,type:`button`,children:n.label},n.value))})}function d({current:n,steps:r}){return(0,e.jsx)(`ol`,{className:`m-progress`,"aria-label":`Progress`,children:r.map((r,i)=>(0,e.jsxs)(`li`,{"aria-current":i===n?`step`:void 0,className:t(`m-progress__step`,i<=n&&`m-progress__step--active`),children:[(0,e.jsx)(`span`,{children:i+1}),(0,e.jsx)(`strong`,{children:r})]},r))})}function f({actions:t,children:n,onClose:i,open:a,title:o}){return a?(0,e.jsxs)(`div`,{className:`m-modal`,role:`presentation`,children:[(0,e.jsx)(`div`,{className:`m-modal__backdrop`,onClick:i}),(0,e.jsxs)(`section`,{"aria-modal":`true`,className:`m-modal__panel`,role:`dialog`,children:[(0,e.jsxs)(`header`,{className:`m-modal__header`,children:[(0,e.jsx)(`h2`,{children:o}),(0,e.jsx)(r,{"aria-label":`Close modal`,onClick:i,variant:`ghost`,children:`Close`})]}),(0,e.jsx)(`div`,{className:`m-modal__body`,children:n}),t?(0,e.jsx)(`footer`,{className:`m-modal__actions`,children:t}):null]})]}):null}exports.AppFrame=a,exports.Button=r,exports.Card=i,exports.Metric=l,exports.Modal=f,exports.ProgressSteps=d,exports.SelectField=s,exports.StatusPill=c,exports.Tabs=u,exports.TextField=o,exports.cx=t,exports.toneClass=n;
package/dist/morass.js ADDED
@@ -0,0 +1,193 @@
1
+ import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
+ //#region src/utils.ts
3
+ function n(...e) {
4
+ return e.filter(Boolean).join(" ");
5
+ }
6
+ function r(e, t) {
7
+ return `${e} ${e}--${t}`;
8
+ }
9
+ //#endregion
10
+ //#region src/components.tsx
11
+ function i({ children: r, className: i, icon: a, type: o = "button", variant: s = "secondary", ...c }) {
12
+ return /* @__PURE__ */ t("button", {
13
+ className: n("m-button", `m-button--${s}`, i),
14
+ type: o,
15
+ ...c,
16
+ children: [a ? /* @__PURE__ */ e("span", {
17
+ className: "m-button__icon",
18
+ children: a
19
+ }) : null, r ? /* @__PURE__ */ e("span", {
20
+ className: "m-button__label",
21
+ children: r
22
+ }) : null]
23
+ });
24
+ }
25
+ function a({ actions: r, children: i, className: a, eyebrow: o, title: s, ...c }) {
26
+ return /* @__PURE__ */ t("section", {
27
+ className: n("m-card", a),
28
+ ...c,
29
+ children: [o || s || r ? /* @__PURE__ */ t("header", {
30
+ className: "m-card__header",
31
+ children: [/* @__PURE__ */ t("div", { children: [o ? /* @__PURE__ */ e("p", {
32
+ className: "m-eyebrow",
33
+ children: o
34
+ }) : null, s ? /* @__PURE__ */ e("h2", {
35
+ className: "m-card__title",
36
+ children: s
37
+ }) : null] }), r ? /* @__PURE__ */ e("div", {
38
+ className: "m-card__actions",
39
+ children: r
40
+ }) : null]
41
+ }) : null, i ? /* @__PURE__ */ e("div", {
42
+ className: "m-card__body",
43
+ children: i
44
+ }) : null]
45
+ });
46
+ }
47
+ function o({ children: n, header: r, nav: i, sidebar: a }) {
48
+ return /* @__PURE__ */ t("div", {
49
+ className: "m-app-frame",
50
+ children: [a ? /* @__PURE__ */ e("aside", {
51
+ className: "m-app-frame__sidebar",
52
+ children: a
53
+ }) : null, /* @__PURE__ */ t("div", {
54
+ className: "m-app-frame__main",
55
+ children: [
56
+ r ? /* @__PURE__ */ e("header", {
57
+ className: "m-app-frame__header",
58
+ children: r
59
+ }) : null,
60
+ /* @__PURE__ */ e("main", {
61
+ className: "m-app-frame__content",
62
+ children: n
63
+ }),
64
+ i ? /* @__PURE__ */ e("nav", {
65
+ className: "m-app-frame__nav",
66
+ children: i
67
+ }) : null
68
+ ]
69
+ })]
70
+ });
71
+ }
72
+ function s({ error: n, helpText: r, label: i, labelProps: a, ...o }) {
73
+ return /* @__PURE__ */ t("label", {
74
+ className: "m-field",
75
+ ...a,
76
+ children: [
77
+ /* @__PURE__ */ e("span", {
78
+ className: "m-field__label",
79
+ children: i
80
+ }),
81
+ /* @__PURE__ */ e("input", {
82
+ className: "m-input",
83
+ ...o
84
+ }),
85
+ r ? /* @__PURE__ */ e("span", {
86
+ className: "m-field__help",
87
+ children: r
88
+ }) : null,
89
+ n ? /* @__PURE__ */ e("span", {
90
+ className: "m-field__error",
91
+ children: n
92
+ }) : null
93
+ ]
94
+ });
95
+ }
96
+ function c({ children: n, error: r, helpText: i, label: a, labelProps: o, ...s }) {
97
+ return /* @__PURE__ */ t("label", {
98
+ className: "m-field",
99
+ ...o,
100
+ children: [
101
+ /* @__PURE__ */ e("span", {
102
+ className: "m-field__label",
103
+ children: a
104
+ }),
105
+ /* @__PURE__ */ e("select", {
106
+ className: "m-input m-input--select",
107
+ ...s,
108
+ children: n
109
+ }),
110
+ i ? /* @__PURE__ */ e("span", {
111
+ className: "m-field__help",
112
+ children: i
113
+ }) : null,
114
+ r ? /* @__PURE__ */ e("span", {
115
+ className: "m-field__error",
116
+ children: r
117
+ }) : null
118
+ ]
119
+ });
120
+ }
121
+ function l({ children: t, tone: n = "neutral" }) {
122
+ return /* @__PURE__ */ e("span", {
123
+ className: r("m-status-pill", n),
124
+ children: t
125
+ });
126
+ }
127
+ function u({ label: n, value: r }) {
128
+ return /* @__PURE__ */ t("div", {
129
+ className: "m-metric",
130
+ children: [/* @__PURE__ */ e("dt", { children: n }), /* @__PURE__ */ e("dd", { children: r })]
131
+ });
132
+ }
133
+ function d({ "aria-label": t, onValueChange: r, tabs: i, value: a }) {
134
+ return /* @__PURE__ */ e("div", {
135
+ "aria-label": t,
136
+ className: "m-tabs",
137
+ role: "tablist",
138
+ children: i.map((t) => /* @__PURE__ */ e("button", {
139
+ "aria-selected": t.value === a,
140
+ className: n("m-tabs__tab", t.value === a && "m-tabs__tab--active"),
141
+ onClick: () => r(t.value),
142
+ role: "tab",
143
+ type: "button",
144
+ children: t.label
145
+ }, t.value))
146
+ });
147
+ }
148
+ function f({ current: r, steps: i }) {
149
+ return /* @__PURE__ */ e("ol", {
150
+ className: "m-progress",
151
+ "aria-label": "Progress",
152
+ children: i.map((i, a) => /* @__PURE__ */ t("li", {
153
+ "aria-current": a === r ? "step" : void 0,
154
+ className: n("m-progress__step", a <= r && "m-progress__step--active"),
155
+ children: [/* @__PURE__ */ e("span", { children: a + 1 }), /* @__PURE__ */ e("strong", { children: i })]
156
+ }, i))
157
+ });
158
+ }
159
+ function p({ actions: n, children: r, onClose: a, open: o, title: s }) {
160
+ return o ? /* @__PURE__ */ t("div", {
161
+ className: "m-modal",
162
+ role: "presentation",
163
+ children: [/* @__PURE__ */ e("div", {
164
+ className: "m-modal__backdrop",
165
+ onClick: a
166
+ }), /* @__PURE__ */ t("section", {
167
+ "aria-modal": "true",
168
+ className: "m-modal__panel",
169
+ role: "dialog",
170
+ children: [
171
+ /* @__PURE__ */ t("header", {
172
+ className: "m-modal__header",
173
+ children: [/* @__PURE__ */ e("h2", { children: s }), /* @__PURE__ */ e(i, {
174
+ "aria-label": "Close modal",
175
+ onClick: a,
176
+ variant: "ghost",
177
+ children: "Close"
178
+ })]
179
+ }),
180
+ /* @__PURE__ */ e("div", {
181
+ className: "m-modal__body",
182
+ children: r
183
+ }),
184
+ n ? /* @__PURE__ */ e("footer", {
185
+ className: "m-modal__actions",
186
+ children: n
187
+ }) : null
188
+ ]
189
+ })]
190
+ }) : null;
191
+ }
192
+ //#endregion
193
+ export { o as AppFrame, i as Button, a as Card, u as Metric, p as Modal, f as ProgressSteps, c as SelectField, l as StatusPill, d as Tabs, s as TextField, n as cx, r as toneClass };
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){switch(e){case`overdue`:return`danger`;case`due-soon`:return`warning`;case`done`:return`success`;case`on-track`:return`info`}}function t(e){if(e<0){let t=Math.abs(e);return`${t} day${t===1?``:`s`} overdue`}return e===0?`Due today`:e===1?`Due tomorrow`:`Due in ${e} days`}exports.formatRelativeDue=t,exports.getDueStateTone=e;
@@ -0,0 +1,5 @@
1
+ import type { Tone } from "./utils";
2
+ export type DueState = "overdue" | "due-soon" | "on-track" | "done";
3
+ export declare function getDueStateTone(state: DueState): Tone;
4
+ export declare function formatRelativeDue(daysUntilDue: number): string;
5
+ //# sourceMappingURL=reminders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminders.d.ts","sourceRoot":"","sources":["../src/reminders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAEpE,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAWrD;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAe9D"}
@@ -0,0 +1,18 @@
1
+ //#region src/reminders.ts
2
+ function e(e) {
3
+ switch (e) {
4
+ case "overdue": return "danger";
5
+ case "due-soon": return "warning";
6
+ case "done": return "success";
7
+ case "on-track": return "info";
8
+ }
9
+ }
10
+ function t(e) {
11
+ if (e < 0) {
12
+ let t = Math.abs(e);
13
+ return `${t} day${t === 1 ? "" : "s"} overdue`;
14
+ }
15
+ return e === 0 ? "Due today" : e === 1 ? "Due tomorrow" : `Due in ${e} days`;
16
+ }
17
+ //#endregion
18
+ export { t as formatRelativeDue, e as getDueStateTone };
@@ -0,0 +1,2 @@
1
+ :root{--m-color-bg:#f7f4ef;--m-color-surface:#fff;--m-color-surface-muted:#f0f7f4;--m-color-text:#1d2524;--m-color-text-muted:#5f6d6a;--m-color-border:#d9ded8;--m-color-primary:#1d766f;--m-color-primary-strong:#115c56;--m-color-danger:#b42318;--m-color-danger-bg:#fef3f2;--m-color-warning:#b45309;--m-color-warning-bg:#fff7ed;--m-color-success:#047857;--m-color-success-bg:#ecfdf3;--m-color-info:#1d4ed8;--m-color-info-bg:#eff6ff;--m-radius:8px;--m-shadow:0 16px 40px #1d252414;--m-font:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif}*{box-sizing:border-box}body{background:var(--m-color-bg);color:var(--m-color-text);font-family:var(--m-font);margin:0}.m-app-frame{grid-template-columns:248px minmax(0,1fr);min-height:100vh;display:grid}.m-app-frame__sidebar{color:#f8faf8;background:#143330;min-height:100vh;padding:20px 16px}.m-app-frame__main{grid-template-rows:auto minmax(0,1fr) auto;min-width:0;display:grid}.m-app-frame__header{border-bottom:1px solid var(--m-color-border);z-index:5;background:#ffffffeb;align-items:center;gap:16px;min-height:64px;padding:12px 24px;display:flex;position:sticky;top:0}.m-app-frame__content{min-width:0;padding:24px}.m-app-frame__nav{background:var(--m-color-surface);border-top:1px solid var(--m-color-border);gap:8px;padding:8px;display:none}.m-button{border-radius:var(--m-radius);cursor:pointer;font:inherit;border:1px solid #0000;justify-content:center;align-items:center;gap:8px;min-height:40px;padding:8px 14px;font-weight:700;transition:background .12s,border-color .12s,color .12s;display:inline-flex}.m-button:disabled{cursor:not-allowed;opacity:.55}.m-button--primary{background:var(--m-color-primary);color:#fff}.m-button--primary:hover{background:var(--m-color-primary-strong)}.m-button--secondary{background:var(--m-color-surface);border-color:var(--m-color-border);color:var(--m-color-text)}.m-button--secondary:hover,.m-button--ghost:hover{background:var(--m-color-surface-muted)}.m-button--ghost{color:inherit;background:0 0}.m-button--danger{background:var(--m-color-danger);color:#fff}.m-button__icon{align-items:center;display:inline-flex}.m-card{background:var(--m-color-surface);border:1px solid var(--m-color-border);border-radius:var(--m-radius);box-shadow:var(--m-shadow);min-width:0}.m-card__header{border-bottom:1px solid var(--m-color-border);justify-content:space-between;align-items:flex-start;gap:16px;padding:16px 18px;display:flex}.m-card__title{margin:0;font-size:1rem;line-height:1.3}.m-card__actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.m-card__body{padding:16px 18px}.m-eyebrow{color:var(--m-color-text-muted);letter-spacing:0;text-transform:uppercase;margin:0 0 4px;font-size:.76rem;font-weight:800}.m-field{gap:6px;display:grid}.m-field__label{color:var(--m-color-text);font-size:.86rem;font-weight:700}.m-field__help,.m-field__error{font-size:.78rem}.m-field__help{color:var(--m-color-text-muted)}.m-field__error{color:var(--m-color-danger)}.m-input{border:1px solid var(--m-color-border);border-radius:var(--m-radius);color:var(--m-color-text);font:inherit;background:#fff;width:100%;min-height:42px;padding:9px 11px}.m-input:focus,.m-button:focus-visible,.m-tabs__tab:focus-visible{outline-offset:2px;outline:3px solid #1d766f40}.m-status-pill{border-radius:999px;align-items:center;min-height:24px;padding:3px 9px;font-size:.78rem;font-weight:800;display:inline-flex}.m-status-pill--neutral{color:#384642;background:#eef1ef}.m-status-pill--info{background:var(--m-color-info-bg);color:var(--m-color-info)}.m-status-pill--success{background:var(--m-color-success-bg);color:var(--m-color-success)}.m-status-pill--warning{background:var(--m-color-warning-bg);color:var(--m-color-warning)}.m-status-pill--danger{background:var(--m-color-danger-bg);color:var(--m-color-danger)}.m-metric{gap:3px;display:grid}.m-metric dt{color:var(--m-color-text-muted);margin:0;font-size:.78rem;font-weight:700}.m-metric dd{margin:0;font-size:1.35rem;font-weight:800}.m-tabs{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.m-tabs__tab{color:var(--m-color-text-muted);cursor:pointer;font:inherit;background:0 0;border:1px solid #0000;border-radius:999px;min-height:34px;padding:6px 13px;font-size:.86rem;font-weight:800}.m-tabs__tab--active{background:var(--m-color-text);color:#fff}.m-progress{gap:10px;margin:0;padding:0;list-style:none;display:grid}.m-progress__step{color:var(--m-color-text-muted);grid-template-columns:28px minmax(0,1fr);align-items:center;gap:10px;display:grid}.m-progress__step span{background:#e6e9e6;border-radius:50%;justify-content:center;align-items:center;width:28px;height:28px;font-weight:800;display:inline-flex}.m-progress__step--active{color:var(--m-color-text)}.m-progress__step--active span{background:var(--m-color-primary);color:#fff}.m-modal{z-index:20;position:fixed;inset:0}.m-modal__backdrop{background:#0f172a70;position:absolute;inset:0}.m-modal__panel{background:var(--m-color-surface);border-radius:var(--m-radius);width:100%;max-width:min(620px,100vw - 32px);max-height:min(720px,100vh - 32px);position:absolute;top:50%;left:50%;overflow:auto;transform:translate(-50%,-50%);box-shadow:0 24px 80px #0f172a3d}.m-modal__header,.m-modal__actions{justify-content:space-between;align-items:center;gap:12px;padding:16px 18px;display:flex}.m-modal__header{border-bottom:1px solid var(--m-color-border)}.m-modal__header h2{margin:0;font-size:1.1rem}.m-modal__body{gap:14px;padding:18px;display:grid}.m-modal__actions{border-top:1px solid var(--m-color-border);justify-content:flex-end}@media (width<=820px){.m-app-frame{grid-template-columns:1fr}.m-app-frame__sidebar{display:none}.m-app-frame__content{padding:16px}.m-app-frame__nav{justify-content:space-around;display:flex;position:sticky;bottom:0}}
2
+ /*$vite$:1*/
@@ -0,0 +1,4 @@
1
+ export declare function cx(...values: Array<string | false | null | undefined>): string;
2
+ export type Tone = "neutral" | "info" | "success" | "warning" | "danger";
3
+ export declare function toneClass(prefix: string, tone: Tone): string;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,EAAE,CAChB,GAAG,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,GAClD,MAAM,CAER;AAED,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEzE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAE5D"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@effigy-analytics/morass",
3
+ "version": "0.2.0",
4
+ "description": "Composable React UI primitives for durable product interfaces.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Effigy Analytics",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/effigy-analytics/morass.git"
11
+ },
12
+ "sideEffects": [
13
+ "**/*.css"
14
+ ],
15
+ "main": "./dist/morass.cjs",
16
+ "module": "./dist/morass.js",
17
+ "types": "./dist/index.d.ts",
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/morass.js",
26
+ "require": "./dist/morass.cjs"
27
+ },
28
+ "./reminders": {
29
+ "types": "./dist/reminders.d.ts",
30
+ "import": "./dist/reminders.js",
31
+ "require": "./dist/reminders.cjs"
32
+ },
33
+ "./styles.css": "./dist/styles.css"
34
+ },
35
+ "scripts": {
36
+ "build": "vite build && tsc -p tsconfig.build.json",
37
+ "check": "npm run format:check && npm run lint && npm run typecheck && npm run test && npm run build && npm run pack:check",
38
+ "dev": "vite --host 0.0.0.0",
39
+ "format": "prettier --write .",
40
+ "format:check": "prettier --check .",
41
+ "lint": "eslint .",
42
+ "pack:check": "npm_config_cache=${TMPDIR:-/tmp}/morass-npm-cache npm pack --dry-run",
43
+ "test": "vitest run",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit"
45
+ },
46
+ "peerDependencies": {
47
+ "react": "^18.2.0 || ^19.0.0",
48
+ "react-dom": "^18.2.0 || ^19.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@eslint/js": "^10.0.1",
52
+ "@types/node": "^26.1.0",
53
+ "@types/react": "^19.1.8",
54
+ "@types/react-dom": "^19.1.6",
55
+ "@vitejs/plugin-react": "^6.0.3",
56
+ "eslint": "^10.6.0",
57
+ "globals": "^17.7.0",
58
+ "prettier": "^3.9.4",
59
+ "typescript": "^6.0.3",
60
+ "typescript-eslint": "^8.62.1",
61
+ "vite": "^8.1.1",
62
+ "vitest": "^4.1.10"
63
+ }
64
+ }