@livenetworks/ashlar 1.3.2
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/README.md +177 -0
- package/js/COMPONENTS.md +1102 -0
- package/js/index.js +41 -0
- package/js/ln-accordion/README.md +137 -0
- package/js/ln-accordion/ln-accordion.js +1 -0
- package/js/ln-accordion/src/ln-accordion.js +41 -0
- package/js/ln-ajax/README.md +91 -0
- package/js/ln-ajax/ln-ajax.js +1 -0
- package/js/ln-ajax/src/ln-ajax.js +277 -0
- package/js/ln-api-connector/README.md +150 -0
- package/js/ln-api-connector/ln-api-connector.js +1 -0
- package/js/ln-api-connector/src/ln-api-connector.js +265 -0
- package/js/ln-autoresize/README.md +80 -0
- package/js/ln-autoresize/ln-autoresize.js +1 -0
- package/js/ln-autoresize/src/ln-autoresize.js +47 -0
- package/js/ln-autosave/README.md +92 -0
- package/js/ln-autosave/ln-autosave.js +1 -0
- package/js/ln-autosave/src/ln-autosave.js +147 -0
- package/js/ln-circular-progress/README.md +161 -0
- package/js/ln-circular-progress/ln-circular-progress.js +1 -0
- package/js/ln-circular-progress/src/ln-circular-progress.js +133 -0
- package/js/ln-confirm/README.md +86 -0
- package/js/ln-confirm/_ln-confirm.scss +13 -0
- package/js/ln-confirm/ln-confirm.js +1 -0
- package/js/ln-confirm/src/ln-confirm.js +131 -0
- package/js/ln-core/crypto.js +83 -0
- package/js/ln-core/helpers.js +411 -0
- package/js/ln-core/index.js +5 -0
- package/js/ln-core/persist.js +71 -0
- package/js/ln-core/positioning.js +207 -0
- package/js/ln-core/reactive.js +74 -0
- package/js/ln-couchdb-connector/README.md +156 -0
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
- package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +348 -0
- package/js/ln-data-coordinator/README.md +165 -0
- package/js/ln-data-coordinator/ln-data-coordinator.js +1 -0
- package/js/ln-data-coordinator/src/ln-data-coordinator.js +249 -0
- package/js/ln-data-store/README.md +94 -0
- package/js/ln-data-store/ln-data-store.js +1 -0
- package/js/ln-data-store/src/ln-data-store.js +699 -0
- package/js/ln-data-table/README.md +110 -0
- package/js/ln-data-table/ln-data-table.js +1 -0
- package/js/ln-data-table/ln-data-table.scss +10 -0
- package/js/ln-data-table/src/ln-data-table.js +1103 -0
- package/js/ln-date/README.md +151 -0
- package/js/ln-date/ln-date.js +1 -0
- package/js/ln-date/src/ln-date.js +442 -0
- package/js/ln-dropdown/README.md +117 -0
- package/js/ln-dropdown/ln-dropdown.js +1 -0
- package/js/ln-dropdown/ln-dropdown.scss +15 -0
- package/js/ln-dropdown/src/ln-dropdown.js +174 -0
- package/js/ln-external-links/README.md +341 -0
- package/js/ln-external-links/ln-external-links.js +1 -0
- package/js/ln-external-links/src/ln-external-links.js +116 -0
- package/js/ln-filter/README.md +99 -0
- package/js/ln-filter/ln-filter.js +1 -0
- package/js/ln-filter/ln-filter.scss +7 -0
- package/js/ln-filter/src/ln-filter.js +404 -0
- package/js/ln-form/README.md +101 -0
- package/js/ln-form/ln-form.js +1 -0
- package/js/ln-form/src/ln-form.js +199 -0
- package/js/ln-http/README.md +89 -0
- package/js/ln-http/ln-http.js +1 -0
- package/js/ln-http/src/ln-http.js +219 -0
- package/js/ln-icons/README.md +88 -0
- package/js/ln-icons/ln-icons.js +1 -0
- package/js/ln-icons/src/ln-icons.js +169 -0
- package/js/ln-link/README.md +303 -0
- package/js/ln-link/ln-link.js +1 -0
- package/js/ln-link/src/ln-link.js +196 -0
- package/js/ln-modal/README.md +154 -0
- package/js/ln-modal/ln-modal.js +1 -0
- package/js/ln-modal/ln-modal.scss +11 -0
- package/js/ln-modal/src/ln-modal.js +201 -0
- package/js/ln-nav/README.md +70 -0
- package/js/ln-nav/ln-nav.js +1 -0
- package/js/ln-nav/src/ln-nav.js +177 -0
- package/js/ln-number/README.md +122 -0
- package/js/ln-number/ln-number.js +1 -0
- package/js/ln-number/src/ln-number.js +302 -0
- package/js/ln-popover/README.md +127 -0
- package/js/ln-popover/ln-popover.js +1 -0
- package/js/ln-popover/src/ln-popover.js +288 -0
- package/js/ln-progress/README.md +442 -0
- package/js/ln-progress/ln-progress.js +1 -0
- package/js/ln-progress/src/ln-progress.js +150 -0
- package/js/ln-search/README.md +83 -0
- package/js/ln-search/ln-search.js +1 -0
- package/js/ln-search/ln-search.scss +7 -0
- package/js/ln-search/src/ln-search.js +114 -0
- package/js/ln-sortable/README.md +95 -0
- package/js/ln-sortable/ln-sortable.js +1 -0
- package/js/ln-sortable/src/ln-sortable.js +203 -0
- package/js/ln-table/README.md +101 -0
- package/js/ln-table/ln-table-sort.js +1 -0
- package/js/ln-table/ln-table.js +1 -0
- package/js/ln-table/ln-table.scss +11 -0
- package/js/ln-table/src/ln-table-sort.js +168 -0
- package/js/ln-table/src/ln-table.js +473 -0
- package/js/ln-tabs/README.md +137 -0
- package/js/ln-tabs/ln-tabs.js +1 -0
- package/js/ln-tabs/src/ln-tabs.js +171 -0
- package/js/ln-time/README.md +81 -0
- package/js/ln-time/ln-time.js +1 -0
- package/js/ln-time/src/ln-time.js +192 -0
- package/js/ln-toast/README.md +122 -0
- package/js/ln-toast/ln-toast.js +15 -0
- package/js/ln-toast/src/ln-toast.js +210 -0
- package/js/ln-toast/template.html +14 -0
- package/js/ln-toggle/README.md +137 -0
- package/js/ln-toggle/ln-toggle.js +1 -0
- package/js/ln-toggle/src/ln-toggle.js +139 -0
- package/js/ln-tooltip/README.md +58 -0
- package/js/ln-tooltip/ln-tooltip.js +1 -0
- package/js/ln-tooltip/ln-tooltip.scss +9 -0
- package/js/ln-tooltip/src/ln-tooltip.js +169 -0
- package/js/ln-translations/README.md +96 -0
- package/js/ln-translations/ln-translations.js +1 -0
- package/js/ln-translations/src/ln-translations.js +275 -0
- package/js/ln-upload/README.md +180 -0
- package/js/ln-upload/ln-upload.js +1 -0
- package/js/ln-upload/ln-upload.scss +20 -0
- package/js/ln-upload/src/ln-upload.js +407 -0
- package/js/ln-validate/README.md +108 -0
- package/js/ln-validate/ln-validate.js +1 -0
- package/js/ln-validate/src/ln-validate.js +160 -0
- package/package.json +55 -0
- package/scss/base/_global.scss +83 -0
- package/scss/base/_reset.scss +17 -0
- package/scss/base/_typography.scss +125 -0
- package/scss/components/_accordion.scss +34 -0
- package/scss/components/_ajax.scss +15 -0
- package/scss/components/_alert.scss +5 -0
- package/scss/components/_app-shell.scss +15 -0
- package/scss/components/_avatar.scss +6 -0
- package/scss/components/_breadcrumbs.scss +33 -0
- package/scss/components/_button.scss +20 -0
- package/scss/components/_card.scss +10 -0
- package/scss/components/_chip.scss +5 -0
- package/scss/components/_circular-progress.scss +29 -0
- package/scss/components/_confirm.scss +5 -0
- package/scss/components/_data-table.scss +83 -0
- package/scss/components/_dropdown.scss +25 -0
- package/scss/components/_empty-state.scss +22 -0
- package/scss/components/_form.scss +100 -0
- package/scss/components/_layout.scss +8 -0
- package/scss/components/_link.scss +11 -0
- package/scss/components/_ln-table.scss +60 -0
- package/scss/components/_loader.scss +6 -0
- package/scss/components/_modal.scss +20 -0
- package/scss/components/_nav.scss +9 -0
- package/scss/components/_page-header.scss +10 -0
- package/scss/components/_popover.scss +10 -0
- package/scss/components/_progress.scss +17 -0
- package/scss/components/_prose.scss +5 -0
- package/scss/components/_scrollbar.scss +32 -0
- package/scss/components/_sections.scss +12 -0
- package/scss/components/_sidebar.scss +5 -0
- package/scss/components/_stat-card.scss +5 -0
- package/scss/components/_status-badge.scss +4 -0
- package/scss/components/_stepper.scss +5 -0
- package/scss/components/_table.scss +19 -0
- package/scss/components/_tabs.scss +21 -0
- package/scss/components/_timeline.scss +14 -0
- package/scss/components/_toast.scss +41 -0
- package/scss/components/_toggle.scss +81 -0
- package/scss/components/_tooltip.scss +18 -0
- package/scss/components/_translations.scss +111 -0
- package/scss/components/_upload.scss +51 -0
- package/scss/config/_breakpoints.scss +72 -0
- package/scss/config/_density.scss +117 -0
- package/scss/config/_icons.scss +37 -0
- package/scss/config/_mixins.scss +13 -0
- package/scss/config/_theme.scss +216 -0
- package/scss/config/_tokens.scss +419 -0
- package/scss/config/mixins/_accordion.scss +52 -0
- package/scss/config/mixins/_ajax.scss +39 -0
- package/scss/config/mixins/_alert.scss +82 -0
- package/scss/config/mixins/_app-shell.scss +312 -0
- package/scss/config/mixins/_avatar.scss +109 -0
- package/scss/config/mixins/_borders.scss +36 -0
- package/scss/config/mixins/_breadcrumbs.scss +72 -0
- package/scss/config/mixins/_breakpoints.scss +62 -0
- package/scss/config/mixins/_btn.scss +179 -0
- package/scss/config/mixins/_card.scss +338 -0
- package/scss/config/mixins/_chip.scss +66 -0
- package/scss/config/mixins/_circular-progress.scss +71 -0
- package/scss/config/mixins/_collapsible.scss +24 -0
- package/scss/config/mixins/_colors.scss +46 -0
- package/scss/config/mixins/_confirm.scss +31 -0
- package/scss/config/mixins/_data-table.scss +346 -0
- package/scss/config/mixins/_display.scss +32 -0
- package/scss/config/mixins/_dropdown.scss +143 -0
- package/scss/config/mixins/_empty-state.scss +30 -0
- package/scss/config/mixins/_focus.scss +55 -0
- package/scss/config/mixins/_footer.scss +42 -0
- package/scss/config/mixins/_form.scss +601 -0
- package/scss/config/mixins/_index.scss +58 -0
- package/scss/config/mixins/_interaction.scss +15 -0
- package/scss/config/mixins/_kbd.scss +22 -0
- package/scss/config/mixins/_layout.scss +117 -0
- package/scss/config/mixins/_link.scss +55 -0
- package/scss/config/mixins/_ln-table.scss +420 -0
- package/scss/config/mixins/_loader.scss +26 -0
- package/scss/config/mixins/_modal.scss +66 -0
- package/scss/config/mixins/_motion.scss +19 -0
- package/scss/config/mixins/_nav.scss +273 -0
- package/scss/config/mixins/_page-header.scss +69 -0
- package/scss/config/mixins/_popover.scss +25 -0
- package/scss/config/mixins/_position.scss +32 -0
- package/scss/config/mixins/_progress.scss +56 -0
- package/scss/config/mixins/_prose.scss +127 -0
- package/scss/config/mixins/_shadows.scss +8 -0
- package/scss/config/mixins/_sidebar.scss +95 -0
- package/scss/config/mixins/_sizing.scss +6 -0
- package/scss/config/mixins/_spacing.scss +19 -0
- package/scss/config/mixins/_stat-card.scss +68 -0
- package/scss/config/mixins/_status-badge.scss +83 -0
- package/scss/config/mixins/_stepper.scss +78 -0
- package/scss/config/mixins/_table.scss +215 -0
- package/scss/config/mixins/_tabs.scss +64 -0
- package/scss/config/mixins/_timeline.scss +69 -0
- package/scss/config/mixins/_toast.scss +148 -0
- package/scss/config/mixins/_tooltip.scss +111 -0
- package/scss/config/mixins/_transitions.scss +10 -0
- package/scss/config/mixins/_translations.scss +124 -0
- package/scss/config/mixins/_typography.scss +57 -0
- package/scss/config/mixins/_upload.scss +168 -0
- package/scss/ln-ashlar.scss +62 -0
- package/scss/tabler-icons.txt +5039 -0
- package/scss/utilities/_animations.scss +83 -0
- package/scss/utilities/_utilities.scss +49 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
@use 'sass:map';
|
|
2
|
+
@use '../breakpoints' as bp;
|
|
3
|
+
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
// Breakpoint mixins — resolve against $breakpoints map in
|
|
6
|
+
// scss/config/_breakpoints.scss. Never hardcode px inside @media or
|
|
7
|
+
// @container; always use these.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// @include mq-up(md) → @media (min-width: 768px)
|
|
11
|
+
// @include mq-down(lg) → @media (max-width: 1023px)
|
|
12
|
+
// @include cq-up(medium, page-header) → @container page-header (min-width: 880px)
|
|
13
|
+
// @include cq-down(compact) → anonymous @container, max-width: 579px
|
|
14
|
+
//
|
|
15
|
+
// Unknown $name raises @error.
|
|
16
|
+
// ==========================================================================
|
|
17
|
+
|
|
18
|
+
@function _resolve($name) {
|
|
19
|
+
$value: map.get(bp.$breakpoints, $name);
|
|
20
|
+
@if $value == null {
|
|
21
|
+
@error "Unknown breakpoint name: #{$name}. Valid keys: #{map.keys(bp.$breakpoints)}";
|
|
22
|
+
}
|
|
23
|
+
@return $value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@mixin mq-up($name) {
|
|
27
|
+
@media (min-width: _resolve($name)) {
|
|
28
|
+
@content;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@mixin mq-down($name) {
|
|
33
|
+
@media (max-width: _resolve($name) - 1px) {
|
|
34
|
+
@content;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@mixin cq-up($name, $container: null) {
|
|
39
|
+
$min: _resolve($name);
|
|
40
|
+
@if $container {
|
|
41
|
+
@container #{$container} (min-width: #{$min}) {
|
|
42
|
+
@content;
|
|
43
|
+
}
|
|
44
|
+
} @else {
|
|
45
|
+
@container (min-width: #{$min}) {
|
|
46
|
+
@content;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@mixin cq-down($name, $container: null) {
|
|
52
|
+
$max: _resolve($name);
|
|
53
|
+
@if $container {
|
|
54
|
+
@container #{$container} (max-width: #{$max - 1px}) {
|
|
55
|
+
@content;
|
|
56
|
+
}
|
|
57
|
+
} @else {
|
|
58
|
+
@container (max-width: #{$max - 1px}) {
|
|
59
|
+
@content;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
@use 'spacing' as *;
|
|
2
|
+
@use 'display' as *;
|
|
3
|
+
@use 'sizing' as *;
|
|
4
|
+
@use 'typography' as *;
|
|
5
|
+
@use 'colors' as *;
|
|
6
|
+
@use 'borders' as *;
|
|
7
|
+
@use 'transitions' as *;
|
|
8
|
+
@use 'interaction' as *;
|
|
9
|
+
@use 'focus' as *;
|
|
10
|
+
|
|
11
|
+
// Buttons
|
|
12
|
+
// button-base — shared neutral chrome (global button + anchor-as-button)
|
|
13
|
+
// btn — accent variant of button-base; rebinds --btn-* to accent colors
|
|
14
|
+
// btn-sm — smaller size modifier
|
|
15
|
+
// btn-lg — larger size modifier
|
|
16
|
+
// btn-group — inline list of peer action buttons (ghost rebind)
|
|
17
|
+
|
|
18
|
+
// ─── button-base ──────────────────────────────────────
|
|
19
|
+
// Neutral chrome shared by <button>, <input type="submit|reset|button">,
|
|
20
|
+
// and anchors used as buttons (e.g. inside form-actions). Reads the
|
|
21
|
+
// six-token --btn-* surface: --btn-bg/fg/border (idle) and
|
|
22
|
+
// --btn-bg-hover/fg-hover/border-hover (hover + active). Both the
|
|
23
|
+
// neutral default and the accent variant are fully token-driven —
|
|
24
|
+
// the difference is which values --btn-* resolves to.
|
|
25
|
+
//
|
|
26
|
+
// Neutral default: --btn-* read from :root, where they wire to
|
|
27
|
+
// --color-bg / --color-fg / --border-strong (and --border-strong-hover
|
|
28
|
+
// companions for the hover state). Theme overrides rebind --btn-*
|
|
29
|
+
// (e.g. Glass rebinds --btn-bg to --bg-elevated, --btn-border
|
|
30
|
+
// to --color-accent for an outlined neutral chrome).
|
|
31
|
+
//
|
|
32
|
+
// Accent variant (submit + @mixin btn): rebinds --btn-* on the
|
|
33
|
+
// consumer element to accent values. Because the rebind happens on
|
|
34
|
+
// the button itself (not at :root), and because @mixin btn first
|
|
35
|
+
// re-declares --color-accent: hsl(var(--color-primary)) at the same
|
|
36
|
+
// scope, .success/.error/.warning/.info classes that override
|
|
37
|
+
// --color-primary cascade through --color-accent → --btn-* →
|
|
38
|
+
// background/color/border-color cleanly. var() always resolves at
|
|
39
|
+
// the declaration site, and the declaration site for both the
|
|
40
|
+
// rebind and button-base's reads is the button element.
|
|
41
|
+
//
|
|
42
|
+
// Why cross-cutting --color-accent-bg-* companions, not per-component
|
|
43
|
+
// --btn-accent-* tokens at :root: a per-component surface declared at
|
|
44
|
+
// :root (--btn-accent-bg: var(--color-accent)) would freeze
|
|
45
|
+
// --color-accent at :root scope and break the
|
|
46
|
+
// .success/.error/.warning/.info cascade for descendant overrides.
|
|
47
|
+
// Cross-cutting --color-accent-bg-* companions (read via fallback to
|
|
48
|
+
// --color-accent / --color-accent-fg) sidestep that: the default
|
|
49
|
+
// theme leaves them unset (mixin falls back to solid + white), Glass
|
|
50
|
+
// rebinds them at theme :root to flip the accent button to
|
|
51
|
+
// translucent. Solid-accent consumers (toast-side, pill-checked,
|
|
52
|
+
// stepper active/complete) read --color-accent / --color-accent-fg
|
|
53
|
+
// directly and are unaffected by Glass's rebind because Glass leaves
|
|
54
|
+
// --color-accent-fg alone. See CLAUDE.md ## Theme Architecture for
|
|
55
|
+
// the full contract.
|
|
56
|
+
|
|
57
|
+
@mixin button-base {
|
|
58
|
+
@include inline-flex;
|
|
59
|
+
@include items-center;
|
|
60
|
+
@include justify-center;
|
|
61
|
+
gap: var(--gap);
|
|
62
|
+
padding: var(--padding-y) var(--padding-x);
|
|
63
|
+
@include text-sm;
|
|
64
|
+
@include font-medium;
|
|
65
|
+
border-radius: var(--radius);
|
|
66
|
+
white-space: nowrap;
|
|
67
|
+
border: var(--border-width) solid var(--btn-border);
|
|
68
|
+
outline: none;
|
|
69
|
+
background: var(--btn-bg);
|
|
70
|
+
color: var(--btn-fg);
|
|
71
|
+
@include transition-colors;
|
|
72
|
+
|
|
73
|
+
&:hover:not(:disabled) {
|
|
74
|
+
background: var(--btn-bg-hover);
|
|
75
|
+
color: var(--btn-fg-hover);
|
|
76
|
+
border-color: var(--btn-border-hover);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:active:not(:disabled) {
|
|
80
|
+
background: var(--btn-bg-hover);
|
|
81
|
+
border-color: var(--btn-border-hover);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&:focus-visible {
|
|
85
|
+
@include focus-ring;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:disabled {
|
|
89
|
+
@include opacity-50;
|
|
90
|
+
@include cursor-not-allowed;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@mixin btn {
|
|
95
|
+
// Accent variant — rebinds the --btn-* token surface to accent
|
|
96
|
+
// values. button-base reads --btn-bg/fg/border (idle) and
|
|
97
|
+
// --btn-bg-hover/fg-hover/border-hover (hover + active), so this
|
|
98
|
+
// mixin only needs to set tokens. No direct background/color/
|
|
99
|
+
// border-color, no &:hover/&:active blocks.
|
|
100
|
+
//
|
|
101
|
+
// Re-declares --color-accent on the consumer element so
|
|
102
|
+
// var(--color-primary) re-resolves at this scope.
|
|
103
|
+
// .success/.error/.warning/.info classes override --color-primary;
|
|
104
|
+
// without these re-declarations, --color-accent stays frozen at
|
|
105
|
+
// :root and semantic colors don't cascade.
|
|
106
|
+
//
|
|
107
|
+
// --color-accent-fg is NOT re-declared — the :root default
|
|
108
|
+
// (hsl(var(--color-white))) already cascades, and re-declaring
|
|
109
|
+
// here would shadow theme companion overrides on solid-only
|
|
110
|
+
// surfaces (which there are none here, but the redundancy is
|
|
111
|
+
// noise either way).
|
|
112
|
+
--color-accent: hsl(var(--color-primary));
|
|
113
|
+
|
|
114
|
+
// Hover state derived from --color-accent at THIS scope via CSS
|
|
115
|
+
// relative color syntax — same hue + saturation, lightness reduced
|
|
116
|
+
// by 8. Computing here (consumer scope) instead of reading a
|
|
117
|
+
// separate :root token means a consumer override (e.g.
|
|
118
|
+
// `style="--color-primary: var(--color-error)"` or a .error
|
|
119
|
+
// ancestor via @mixin semantic-color) cascades to BOTH the idle
|
|
120
|
+
// and hover surfaces — the whole state machine follows from a
|
|
121
|
+
// single token change.
|
|
122
|
+
//
|
|
123
|
+
// IMPORTANT — `calc(l - 8)` not `calc(l - 8%)`. Inside
|
|
124
|
+
// relative color syntax, channel keywords (h/s/l) evaluate to
|
|
125
|
+
// <number> tokens, not <percentage>. `l - 8%` mixes types →
|
|
126
|
+
// invalid color → browser falls back to `transparent` and the
|
|
127
|
+
// hover bg vanishes. The number form is what the spec mandates;
|
|
128
|
+
// hsl(216 95 34) without `%` is valid CSS Color 4 and reads as
|
|
129
|
+
// "lightness 34%" exactly like the legacy hsl(216 95% 34%) form.
|
|
130
|
+
//
|
|
131
|
+
// Pattern shared with @mixin pill, @mixin data-table-row-focused,
|
|
132
|
+
// the anchor hover in _global.scss, and @mixin semantic-color's
|
|
133
|
+
// status-family cascade. -light / -lighter remain explicit tokens
|
|
134
|
+
// (theme-controlled, not derivable from base).
|
|
135
|
+
--color-accent-hover: hsl(from var(--color-accent) h s calc(l - 8));
|
|
136
|
+
|
|
137
|
+
// --btn-bg / --btn-fg read translucent companions via fallback.
|
|
138
|
+
// Default theme: companions unset → falls back to --color-accent
|
|
139
|
+
// / --color-accent-fg (solid + white). Glass theme: companions
|
|
140
|
+
// rebound at :root → translucent fill + accent-colored fg. The
|
|
141
|
+
// var() fallback resolves at the consumer (this button), so the
|
|
142
|
+
// .success/.error/.warning/.info cascade through --color-primary
|
|
143
|
+
// still works in both themes.
|
|
144
|
+
--btn-bg: var(--color-accent-bg, var(--color-accent));
|
|
145
|
+
--btn-fg: var(--color-accent-bg-fg, var(--color-accent-fg));
|
|
146
|
+
--btn-border: var(--color-accent);
|
|
147
|
+
--btn-bg-hover: var(--color-accent-bg-hover, var(--color-accent-hover));
|
|
148
|
+
--btn-fg-hover: var(--color-accent-bg-fg, var(--color-accent-fg));
|
|
149
|
+
--btn-border-hover: var(--color-accent-hover);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@mixin btn-sm {
|
|
153
|
+
--btn-padding-x: var(--size-sm-up);
|
|
154
|
+
--gap: var(--size-xs);
|
|
155
|
+
gap: var(--gap);
|
|
156
|
+
@include text-xs;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@mixin btn-lg {
|
|
160
|
+
--btn-padding-x: var(--size-lg);
|
|
161
|
+
--btn-padding-y: var(--size-md);
|
|
162
|
+
--gap: var(--size-sm-up);
|
|
163
|
+
gap: var(--gap);
|
|
164
|
+
@include text-base;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@mixin btn-group {
|
|
168
|
+
--gap: var(--size-xs);
|
|
169
|
+
@include inline-flex;
|
|
170
|
+
@include items-center;
|
|
171
|
+
gap: var(--gap);
|
|
172
|
+
|
|
173
|
+
button {
|
|
174
|
+
--btn-bg: transparent;
|
|
175
|
+
--btn-border: transparent;
|
|
176
|
+
color: var(--fg-subtle);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
@use 'spacing' as *;
|
|
2
|
+
@use 'display' as *;
|
|
3
|
+
@use 'sizing' as *;
|
|
4
|
+
@use 'typography' as *;
|
|
5
|
+
@use 'colors' as *;
|
|
6
|
+
@use 'borders' as *;
|
|
7
|
+
@use 'shadows' as *;
|
|
8
|
+
@use 'transitions' as *;
|
|
9
|
+
@use 'position' as *;
|
|
10
|
+
|
|
11
|
+
// Card & Section — composite mixins
|
|
12
|
+
|
|
13
|
+
@mixin card {
|
|
14
|
+
background: var(--color-bg);
|
|
15
|
+
@include border;
|
|
16
|
+
@include w-full;
|
|
17
|
+
@include flex-col;
|
|
18
|
+
border-radius: var(--radius);
|
|
19
|
+
@include overflow-hidden;
|
|
20
|
+
@include transition;
|
|
21
|
+
--shadow: var(--shadow-resting);
|
|
22
|
+
box-shadow: var(--shadow);
|
|
23
|
+
|
|
24
|
+
&:hover {
|
|
25
|
+
--color-border: var(--border-strong);
|
|
26
|
+
--shadow: var(--shadow-floating);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Direct-child selectors only — nested <header>/<main>/<footer>
|
|
30
|
+
// inside card content are consumer-owned and must not inherit the
|
|
31
|
+
// card's chrome. Same rationale as @mixin section-card.
|
|
32
|
+
> header { @include panel-header; }
|
|
33
|
+
> main { @include panel-body; }
|
|
34
|
+
> footer { @include panel-footer; }
|
|
35
|
+
|
|
36
|
+
// Card-tile behavior: main stretches to equalize heights when
|
|
37
|
+
// cards are placed in a grid row, and provides rhythm between
|
|
38
|
+
// stacked children (h3, p, .field) via the logical gap token.
|
|
39
|
+
> main {
|
|
40
|
+
@include flex-1;
|
|
41
|
+
gap: var(--gap);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Whole-card-as-link: <a> wraps card content and fills the card.
|
|
45
|
+
> a {
|
|
46
|
+
@include flex-col;
|
|
47
|
+
@include flex-1;
|
|
48
|
+
text-decoration: none;
|
|
49
|
+
color: inherit;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Tile-header h3: when a card carries a title inside > main
|
|
53
|
+
// without a <header> wrapper, the global h3 cascade (heading-sm)
|
|
54
|
+
// is too large for tile context. Tighten to tile-title sizing.
|
|
55
|
+
> main h3 {
|
|
56
|
+
font-size: var(--text-body-sm);
|
|
57
|
+
@include font-semibold;
|
|
58
|
+
color: inherit;
|
|
59
|
+
margin: 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@mixin panel-header {
|
|
64
|
+
@include flex;
|
|
65
|
+
@include items-center;
|
|
66
|
+
@include justify-between;
|
|
67
|
+
padding: var(--padding-y) var(--padding-x);
|
|
68
|
+
@include border-b;
|
|
69
|
+
--color-bg: var(--bg-sunken);
|
|
70
|
+
background: var(--color-bg);
|
|
71
|
+
@include transition;
|
|
72
|
+
|
|
73
|
+
h3 {
|
|
74
|
+
font-size: var(--text-body-sm);
|
|
75
|
+
line-height: var(--lh-body-sm);
|
|
76
|
+
@include font-medium;
|
|
77
|
+
color: var(--color-fg);
|
|
78
|
+
margin: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Equalize control chrome inside the header. Geometric height lock
|
|
82
|
+
// matching @mixin app-header-actions: icon-content (1.25rem) + 2 ×
|
|
83
|
+
// rebound --padding-y + 2 × border-width. Buttons inherit --padding-y
|
|
84
|
+
// from this rebind; search-icon labels read it from
|
|
85
|
+
// @mixin form-input-icon-group (same var(--size-xs) value), so the
|
|
86
|
+
// formula resolves identically for both. Descendant selector — these
|
|
87
|
+
// controls are commonly wrapped in <aside>/<nav>/<div> inside the
|
|
88
|
+
// header. panel-header is chrome (no body labels), so descendant
|
|
89
|
+
// `label` here is always a search-icon-group, never a field label.
|
|
90
|
+
label {
|
|
91
|
+
--padding-y: var(--size-xs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
button {
|
|
95
|
+
--btn-padding-y: var(--size-xs);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:is(button, label) {
|
|
99
|
+
min-height: calc(1.25rem + 2 * var(--padding-y) + 2 * var(--border-width));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Close/dismiss and toggle buttons inside the header should be tight and flat.
|
|
103
|
+
button[data-ln-modal-close],
|
|
104
|
+
button[aria-label="Close"],
|
|
105
|
+
button[data-ln-toggle] {
|
|
106
|
+
--btn-padding-y: var(--size-2xs);
|
|
107
|
+
--btn-padding-x: var(--size-2xs);
|
|
108
|
+
--shadow: none;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@mixin panel-body {
|
|
113
|
+
padding: var(--padding-y) var(--padding-x);
|
|
114
|
+
|
|
115
|
+
// Auto-flush: ONLY when the table (or .table-container) is the
|
|
116
|
+
// sole child of main — i.e. the card is a pure table card.
|
|
117
|
+
// Strip padding so the table spans edge-to-edge, and drop the
|
|
118
|
+
// table's own radius/shadow (card's overflow:hidden handles
|
|
119
|
+
// rounded corners).
|
|
120
|
+
//
|
|
121
|
+
// If main has mixed content (intro <p>, demo-split, <h4>,
|
|
122
|
+
// then <table>), :only-child doesn't match, padding stays,
|
|
123
|
+
// and the table keeps its own inset.
|
|
124
|
+
&:has(> table:only-child),
|
|
125
|
+
&:has(> .table-container:only-child) {
|
|
126
|
+
padding: 0;
|
|
127
|
+
|
|
128
|
+
> table,
|
|
129
|
+
> .table-container > table {
|
|
130
|
+
border-radius: 0;
|
|
131
|
+
box-shadow: none;
|
|
132
|
+
margin-bottom: 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@mixin panel-footer {
|
|
138
|
+
padding: var(--padding-y) var(--padding-x);
|
|
139
|
+
@include border-t;
|
|
140
|
+
@include flex;
|
|
141
|
+
@include justify-end;
|
|
142
|
+
gap: var(--gap);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@mixin section {
|
|
146
|
+
--margin-block: var(--size-xl);
|
|
147
|
+
margin-bottom: var(--margin-block);
|
|
148
|
+
|
|
149
|
+
header {
|
|
150
|
+
@include flex;
|
|
151
|
+
@include items-center;
|
|
152
|
+
@include justify-between;
|
|
153
|
+
--margin-block: var(--size-md);
|
|
154
|
+
margin-bottom: var(--margin-block);
|
|
155
|
+
--padding-y: var(--size-sm);
|
|
156
|
+
padding-bottom: var(--padding-y);
|
|
157
|
+
@include border-b;
|
|
158
|
+
|
|
159
|
+
h2 {
|
|
160
|
+
@include text-xl;
|
|
161
|
+
@include font-bold;
|
|
162
|
+
color: var(--color-fg);
|
|
163
|
+
margin: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.section-actions {
|
|
167
|
+
@include flex;
|
|
168
|
+
gap: var(--gap);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main {
|
|
173
|
+
padding: 0;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ─── Card accents (Tabler-inspired colored lines) ──────
|
|
178
|
+
// Accent reads --color-accent (solid) for borders, --color-primary
|
|
179
|
+
// (raw triplet) for alpha hover tints — see plan §0.3.
|
|
180
|
+
// Usage: #my-card { @include card; @include card-accent-top; }
|
|
181
|
+
|
|
182
|
+
@mixin _card-accent-base {
|
|
183
|
+
&:hover {
|
|
184
|
+
background-color: color-mix(in srgb, var(--color-accent) 4%, transparent);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@mixin card-accent-top {
|
|
189
|
+
@include _card-accent-base;
|
|
190
|
+
border-top: 3px solid var(--color-accent);
|
|
191
|
+
&:hover {
|
|
192
|
+
border-top-color: var(--color-accent);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@mixin card-accent-bottom {
|
|
197
|
+
@include _card-accent-base;
|
|
198
|
+
border-bottom: 3px solid var(--color-accent);
|
|
199
|
+
&:hover {
|
|
200
|
+
border-bottom-color: var(--color-accent);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@mixin card-accent-left {
|
|
205
|
+
@include _card-accent-base;
|
|
206
|
+
border-left: 3px solid var(--color-accent);
|
|
207
|
+
&:hover {
|
|
208
|
+
border-left-color: var(--color-accent);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ─── Card tinted background ────────────────────────────
|
|
213
|
+
|
|
214
|
+
@mixin card-bg {
|
|
215
|
+
background-color: color-mix(in srgb, var(--color-accent) 6%, transparent);
|
|
216
|
+
border-color: color-mix(in srgb, var(--color-accent) 15%, transparent);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ─── Card stacked (visual depth illusion) ──────────────
|
|
220
|
+
|
|
221
|
+
@mixin card-stacked {
|
|
222
|
+
@include relative;
|
|
223
|
+
|
|
224
|
+
&::after {
|
|
225
|
+
content: '';
|
|
226
|
+
@include absolute;
|
|
227
|
+
bottom: -5px;
|
|
228
|
+
left: 6px;
|
|
229
|
+
right: 6px;
|
|
230
|
+
height: 10px;
|
|
231
|
+
background: var(--color-bg);
|
|
232
|
+
border-radius: var(--radius);
|
|
233
|
+
--shadow: var(--shadow-resting);
|
|
234
|
+
box-shadow: var(--shadow);
|
|
235
|
+
--color-border: var(--border-subtle);
|
|
236
|
+
border: var(--border-width) solid var(--color-border);
|
|
237
|
+
z-index: -1;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@mixin section-card {
|
|
242
|
+
background: var(--color-bg);
|
|
243
|
+
@include border;
|
|
244
|
+
border-radius: var(--radius);
|
|
245
|
+
// `overflow: clip` not `overflow: hidden` — clips at rounded corners
|
|
246
|
+
// without establishing a scroll container, so sticky descendants
|
|
247
|
+
// (e.g. ln-table's <thead>) bind to the outer .app-main > section
|
|
248
|
+
// scroll surface instead of being trapped inside this card.
|
|
249
|
+
overflow: clip;
|
|
250
|
+
@include transition;
|
|
251
|
+
--shadow: var(--shadow-resting);
|
|
252
|
+
box-shadow: var(--shadow);
|
|
253
|
+
--margin-block: var(--size-md);
|
|
254
|
+
margin-bottom: var(--margin-block);
|
|
255
|
+
|
|
256
|
+
// Direct-child selectors only — nested <header>/<main>/<footer>
|
|
257
|
+
// elements inside the card's content are consumer-owned and
|
|
258
|
+
// must not inherit the card's own chrome styles.
|
|
259
|
+
> header { @include panel-header; }
|
|
260
|
+
> main { @include panel-body; }
|
|
261
|
+
> footer { @include panel-footer; }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ─── Floating panel ────────────────────────────────────
|
|
265
|
+
// Chrome recipe for floating overlays (popover, dropdown menu, toast).
|
|
266
|
+
// Rebinds --color-bg to elevated surface and --shadow to floating
|
|
267
|
+
// shadow so floating panels lift off the page surface correctly.
|
|
268
|
+
|
|
269
|
+
@mixin floating-panel {
|
|
270
|
+
--color-bg: var(--bg-elevated);
|
|
271
|
+
--color-border: var(--border-subtle);
|
|
272
|
+
--shadow: var(--shadow-floating);
|
|
273
|
+
background: var(--color-bg);
|
|
274
|
+
border-block-start: var(--border-block-start, var(--border-width) solid var(--color-border));
|
|
275
|
+
border-block-end: var(--border-block-end, var(--border-width) solid var(--color-border));
|
|
276
|
+
border-inline-start: var(--border-inline-start, var(--border-width) solid var(--color-border));
|
|
277
|
+
border-inline-end: var(--border-inline-end, var(--border-width) solid var(--color-border));
|
|
278
|
+
border-radius: var(--radius);
|
|
279
|
+
box-shadow: var(--shadow);
|
|
280
|
+
z-index: var(--z-dropdown);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ─── Card field list (label/value rows) ────────────────
|
|
284
|
+
// Dashboard/settings pattern: card body contains .field rows
|
|
285
|
+
// with .label + .value. Separator between rows, none after last.
|
|
286
|
+
// Apply on a scope that contains .field descendants — typically
|
|
287
|
+
// the `.card` global binding, but any container works.
|
|
288
|
+
//
|
|
289
|
+
// Expected HTML:
|
|
290
|
+
// <div class="card">
|
|
291
|
+
// <main>
|
|
292
|
+
// <div class="field"><span class="label">Name</span><span class="value">Marko</span></div>
|
|
293
|
+
// <div class="field"><span class="label">Email</span><span class="value">m@x</span></div>
|
|
294
|
+
// </main>
|
|
295
|
+
// </div>
|
|
296
|
+
|
|
297
|
+
@mixin card-field-list {
|
|
298
|
+
.field {
|
|
299
|
+
@include flex;
|
|
300
|
+
align-items: baseline;
|
|
301
|
+
@include justify-between;
|
|
302
|
+
gap: var(--gap);
|
|
303
|
+
--padding-y: var(--size-xs-up);
|
|
304
|
+
padding-block: var(--padding-y);
|
|
305
|
+
@include border-b;
|
|
306
|
+
|
|
307
|
+
&:last-child {
|
|
308
|
+
@include border-none;
|
|
309
|
+
padding-bottom: 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.label {
|
|
313
|
+
@include text-xs;
|
|
314
|
+
@include font-semibold;
|
|
315
|
+
@include uppercase;
|
|
316
|
+
@include tracking-wider;
|
|
317
|
+
--color-fg: var(--fg-muted);
|
|
318
|
+
color: var(--color-fg);
|
|
319
|
+
@include flex-shrink-0;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.value {
|
|
323
|
+
@include text-sm;
|
|
324
|
+
@include font-medium;
|
|
325
|
+
color: var(--color-fg);
|
|
326
|
+
text-align: right;
|
|
327
|
+
margin: 0;
|
|
328
|
+
|
|
329
|
+
em {
|
|
330
|
+
--color-fg: var(--fg-subtle);
|
|
331
|
+
color: var(--color-fg);
|
|
332
|
+
@include text-xs;
|
|
333
|
+
font-style: normal;
|
|
334
|
+
font-weight: normal;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
@use 'spacing' as *;
|
|
2
|
+
@use 'display' as *;
|
|
3
|
+
@use 'typography' as *;
|
|
4
|
+
@use 'colors' as *;
|
|
5
|
+
@use 'borders' as *;
|
|
6
|
+
@use 'focus' as *;
|
|
7
|
+
|
|
8
|
+
@mixin chip {
|
|
9
|
+
@include inline-flex;
|
|
10
|
+
@include items-center;
|
|
11
|
+
--gap: var(--size-xs);
|
|
12
|
+
gap: var(--gap);
|
|
13
|
+
--padding-y: var(--size-xs);
|
|
14
|
+
--padding-x: var(--size-sm-up);
|
|
15
|
+
padding: var(--padding-y) var(--padding-x);
|
|
16
|
+
@include typography(label-sm);
|
|
17
|
+
--color-bg: var(--bg-recessed);
|
|
18
|
+
background: var(--color-bg);
|
|
19
|
+
color: var(--color-fg);
|
|
20
|
+
@include rounded-full;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
line-height: 1.4;
|
|
23
|
+
|
|
24
|
+
> button {
|
|
25
|
+
all: unset;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
@include inline-flex-center;
|
|
28
|
+
width: 1rem;
|
|
29
|
+
height: 1rem;
|
|
30
|
+
border-radius: 50%;
|
|
31
|
+
--color-fg: var(--fg-muted);
|
|
32
|
+
color: var(--color-fg);
|
|
33
|
+
|
|
34
|
+
&:hover {
|
|
35
|
+
background: var(--color-border);
|
|
36
|
+
color: var(--color-fg);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:focus-visible {
|
|
40
|
+
@include focus-ring;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
svg.ln-icon {
|
|
44
|
+
width: 0.75rem;
|
|
45
|
+
height: 0.75rem;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Tone variants
|
|
50
|
+
&.success {
|
|
51
|
+
background: hsl(var(--color-success) / 0.12);
|
|
52
|
+
color: hsl(var(--color-success));
|
|
53
|
+
}
|
|
54
|
+
&.warning {
|
|
55
|
+
background: hsl(var(--color-warning) / 0.12);
|
|
56
|
+
color: hsl(var(--color-warning));
|
|
57
|
+
}
|
|
58
|
+
&.error {
|
|
59
|
+
background: hsl(var(--color-error) / 0.12);
|
|
60
|
+
color: hsl(var(--color-error));
|
|
61
|
+
}
|
|
62
|
+
&.info {
|
|
63
|
+
background: hsl(var(--color-info) / 0.12);
|
|
64
|
+
color: hsl(var(--color-info));
|
|
65
|
+
}
|
|
66
|
+
}
|