Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@ registry/styles/shadcn/
# Generated from the copies; formatting would reorder classes and change how
# conflicting classes merge, so docs previews and installs would differ.
registry/styles/adapted/

# Vendored assets and generated Liquid metadata retain their exact bytes.
liquid/vendor/
liquid/LICENSE*
liquid/styles/tokens.css
liquid/contracts.json
liquid/manifest.json
liquid/licenses.json
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ This repository is the Fulldev UI registry source, docs site and reference imple

## Registry

- Native Liquid lives in `liquid/`, with its own `liquid/registry.json`. Follow `liquid/README.md`; its handwritten CSS does not use the Tailwind style generator. Keep shared tokens and part contracts aligned with the other platforms. Shopify settings, commerce adapters and merchant content stay outside the UI registry.

- `registry.json` is the source of truth for installable items. Update it when you add or remove an item or change its files or dependencies. Item metadata is regenerated by `pnpm registry:meta` (part of `pnpm registry:build`); read `scripts/registry-meta.mjs` for which values it overwrites before editing them by hand.
- Docs pages document registry items, but they do not make something installable.
- `public/r` is generated registry output; do not hand-edit it. Run `pnpm registry:build` when registry inputs change and commit the result: `pnpm check` rebuilds the registry and fails on a difference.
Expand Down
6 changes: 5 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ A general homepage for both frameworks, with its content in the frontmatter of `
- Then a selection of components, with the extras React gets from Fulldev UI marked; the block categories with their counts from the registry; the features block; the presets; the FAQ block; and a closing call to action on the primary color. Sections follow the 6xl container; the blocks render as they would on a site, without Preview or Code frames.
- The homepage, like Create, belongs to both frameworks: its links lead to the framework chosen last.

## Liquid

Liquid is the third framework in the shared switcher. It has its own navigation, component pages, native Liquid examples, installation commands and Markdown endpoints under `/liquid/`. Previews render the actual Liquid and CSS in isolated frames, with the shared theme tokens. Native styles stay Vega; Tailwind style presets do not transform Liquid. Shopify blocks and commerce stay theme-owned.

## Presets

The site follows one preset everywhere: theme, style, fonts and menu color, previews included.
Expand All @@ -34,6 +38,6 @@ The site follows one preset everywhere: theme, style, fonts and menu color, prev
## Rejected

- The inset app shell with a collapsible sidebar and breadcrumbs (`Sidebar1`): too busy for docs.
- Per-page Astro/React tabs and a style menu next to every preview: both are global choices in the switcher and on Create.
- Per-page Astro/React/Liquid tabs and a style menu next to every preview: both are global choices in the switcher and on Create.
- Docs without a left navigation: too hard to browse 60+ components.
- On the homepage: blocks in Preview and Code frames, a hero that leads with Astro only, a split hero, install tabs in the hero, and the bordered call to action card (`Cta8`).
9 changes: 8 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import globals from "globals"
import tseslint from "typescript-eslint"

export default defineConfig([
globalIgnores(["dist", ".astro", ".netlify", ".dev", "public/r"]),
globalIgnores([
"dist",
".astro",
".netlify",
".dev",
"public/r",
"liquid/vendor",
]),
{
files: ["**/*.{js,mjs,ts}"],
extends: [js.configs.recommended, tseslint.configs.recommended],
Expand Down
13 changes: 12 additions & 1 deletion knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,27 @@
"src/components/live-code.astro",
// Read by the html-validate CLI in the build.
"html-validate.config.mjs",
"liquid/runtime/*.js",
],
// Read as text by src/lib/styles.ts and the registry scripts.
"ignoreFiles": ["registry/styles/**/*.css"],
"ignoreFiles": [
"registry/styles/**/*.css",
"liquid/vendor/**",
"liquid/styles/*.css",
],
"ignoreIssues": {
// Part of the installed price component, shipped unchanged.
"src/components/ui/price/format-price-value.ts": ["exports"],
},
"ignoreDependencies": [
// Read from node_modules by the Icon component.
"lucide-static",
// Native Liquid resolves these through its Shopify import map.
"@data-slot/carousel",
"@fulldev/lifecycle",
"@fulldev/controls",
"@fulldev/carousel",
"@fulldev/motion",
],
},
"react": {
Expand Down
21 changes: 21 additions & 0 deletions liquid/LICENSE-DATA-SLOT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Bejamas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
21 changes: 21 additions & 0 deletions liquid/LICENSE-FULLDEV.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Fulldev, Sil Veltman

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
21 changes: 21 additions & 0 deletions liquid/LICENSE-SHADCN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 shadcn

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
17 changes: 17 additions & 0 deletions liquid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Fulldev UI for Liquid

Native Shopify Liquid, readable CSS and ES modules. The consumer needs no Tailwind, framework, package manifest or build step. See the [installation and API guide](https://ui.full.dev/liquid/).

`components/` owns each component's styles and optional markup. Most use Shopify's `{% stylesheet %}` tag. Components with global classes, such as typography's `typeset`, keep their CSS in `styles/`, so Shopify Theme Check can resolve those classes across snippets. Shopify bundles the stylesheet tags; the source stays small and separate. Card parts remain native HTML, styled through `data-slot`.

`runtime/` owns initialization, native form fallbacks, asynchronous imports, cleanup, editor section events and block selection. It uses unmodified data-slot controllers in `vendor/`. `snippets/ui.liquid` loads the complete component set once. A theme with commerce adapters uses `runtime: false` and imports the lifecycle and control adapters into its existing initializer.

`registry.json` is the install contract. Every item is universal, every file has an explicit `~/assets/` or `~/snippets/` target, and dependencies use full Liquid registry URLs. Individual items install their prerequisites, including shared popup styles and runtime where needed. `components` is the complete set. `init` is tokens and base styles only.

CSS and Liquid are maintained by hand. The shared neutral palette comes from `registry/styles/shadcn/themes.json`; `styles/primitives.css` holds native sizes, radii, shadows and media roles. Theme colors, settings, content, Shopify forms and layouts remain theme-owned. A consumer loads its scheme overrides after `ui`, and `custom.css` after `content_for_header`.

Registry generation and installation tests are added separately from this source layer. Local LiquidJS fixtures do not verify a store's commerce objects or Shopify's stylesheet subsetting.

This first port follows Vega and the complete reusable storefront layer from `fulldotdev/liquid-template` at `e13fc25`. Sidebar, Resizable, Menubar, Scroll Area and React-only app components are outside this native storefront set. Shopify blocks, commerce adapters, translation keys and settings are not installed by the UI registry. The existing storefront media and card variants are additive to the shared component contract. Other Tailwind presets are not translated automatically.

Vendored modules stay byte-identical to data-slot 1.1.1. Update them together with `vendor.json` and verify the recorded SHA-256 hashes. Every installation includes `assets/ui-licenses.json`, including the original shadcn/ui and data-slot notices. The complete install includes `assets/ui-manifest.json`; consumers can check those hashes to detect drift. Store customizations belong in their own files.
5 changes: 5 additions & 0 deletions liquid/components/accordion.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% doc %}
Fulldev UI accordion styles. Use native markup with its data-slot parts.
{% enddoc %}

{{ 'ui-accordion.css' | asset_url | stylesheet_tag }}
116 changes: 116 additions & 0 deletions liquid/components/alert-dialog.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{% doc %}
Fulldev UI alert-dialog styles. Use native markup with its data-slot parts.
{% enddoc %}

{% stylesheet %}
/* A confirmation over the page, as Vega's alert dialog: a centered stack on phones and in the small
size; from 640px the default size aligns text left with the media beside the title and description. */
[data-slot='alert-dialog-overlay'] {
position: fixed;
inset: 0;
z-index: calc(var(--alert-dialog-overlay-stack-index, 0) * 2 + 100);
background: var(--scrim);
transition: opacity 100ms;
}
@supports (backdrop-filter: blur(4px)) {
[data-slot='alert-dialog-overlay'] {
backdrop-filter: blur(4px);
}
}
[data-slot='alert-dialog-content'] {
position: fixed;
top: 50%;
left: 50%;
z-index: calc(var(--alert-dialog-content-stack-index, 0) * 2 + 101);
display: grid;
gap: calc(var(--spacing) * 6);
width: calc(100% - 2rem);
max-width: 20rem;
padding: calc(var(--spacing) * 6);
border-radius: var(--radius-xl);
background: var(--popover);
color: var(--popover-foreground);
font-size: 0.875rem;
box-shadow: 0 0 0 1px color-mix(in oklch, var(--foreground) 10%, transparent);
outline: none;
translate: -50% -50%;
transition:
opacity 100ms,
scale 100ms;
}
[data-slot='alert-dialog-overlay']:is([data-starting-style], [data-ending-style]) {
opacity: 0;
}
[data-slot='alert-dialog-content']:is([data-starting-style], [data-ending-style]) {
opacity: 0;
scale: 0.95;
}
[data-slot='alert-dialog-header'] {
display: grid;
grid-template-rows: auto 1fr;
place-items: center;
gap: calc(var(--spacing) * 1.5);
text-align: center;
}
[data-slot='alert-dialog-header']:has([data-slot='alert-dialog-media']) {
grid-template-rows: auto auto 1fr;
column-gap: calc(var(--spacing) * 6);
}
[data-slot='alert-dialog-media'] {
display: inline-flex;
align-items: center;
justify-content: center;
width: calc(var(--spacing) * 16);
height: calc(var(--spacing) * 16);
margin-bottom: calc(var(--spacing) * 2);
border-radius: var(--radius-md);
background: var(--muted);
}
[data-slot='alert-dialog-media'] > .icon {
width: calc(var(--spacing) * 8);
height: calc(var(--spacing) * 8);
}
[data-slot='alert-dialog-title'] {
font-size: 1.125rem;
font-weight: 500;
letter-spacing: var(--tracking-normal);
}
[data-slot='alert-dialog-description'] {
color: var(--muted-foreground);
text-wrap: balance;
}
[data-slot='alert-dialog-footer'] {
display: flex;
flex-direction: column-reverse;
gap: calc(var(--spacing) * 2);
}
[data-slot='alert-dialog-content'][data-size='sm'] [data-slot='alert-dialog-footer'] {
display: grid;
grid-template-columns: 1fr 1fr;
}
@media (min-width: 640px) {
[data-slot='alert-dialog-content']:not([data-size='sm']) {
max-width: 32rem;
}
[data-slot='alert-dialog-content']:not([data-size='sm']) [data-slot='alert-dialog-header'] {
place-items: start;
text-align: left;
}
[data-slot='alert-dialog-content']:not([data-size='sm'])
[data-slot='alert-dialog-header']:has([data-slot='alert-dialog-media']) {
grid-template-rows: auto 1fr;
}
[data-slot='alert-dialog-content']:not([data-size='sm']) [data-slot='alert-dialog-media'] {
grid-row: span 2;
}
[data-slot='alert-dialog-content']:not([data-size='sm'])
[data-slot='alert-dialog-header']:has([data-slot='alert-dialog-media'])
> [data-slot='alert-dialog-title'] {
grid-column-start: 2;
}
[data-slot='alert-dialog-content']:not([data-size='sm']) [data-slot='alert-dialog-footer'] {
flex-direction: row;
justify-content: flex-end;
}
}
{% endstylesheet %}
45 changes: 45 additions & 0 deletions liquid/components/alert.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{% doc %}
Fulldev UI alert styles. Use native markup with its data-slot parts.
{% enddoc %}

{% stylesheet %}
[data-slot='alert'] {
display: grid;
gap: calc(var(--spacing) * 0.5);
padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
background: var(--card);
color: var(--card-foreground);
font-size: 0.875rem;
text-align: left;
}
[data-slot='alert']:has(> .icon) {
grid-template-columns: auto 1fr;
column-gap: calc(var(--spacing) * 2.5);
}
[data-slot='alert'] > .icon {
grid-row: span 2;
width: calc(var(--spacing) * 4);
height: calc(var(--spacing) * 4);
translate: 0 calc(var(--spacing) * 0.5);
color: currentcolor;
}
[data-slot='alert'][data-variant='destructive'] {
color: var(--destructive);
}
[data-slot='alert-title'] {
font-weight: 500;
}
[data-slot='alert-description'] {
color: var(--muted-foreground);
text-wrap: balance;
}
[data-slot='alert'][data-variant='destructive'] [data-slot='alert-description'] {
color: color-mix(in oklch, var(--destructive) 90%, transparent);
}
[data-slot='alert'] ul {
margin: 0;
padding-left: calc(var(--spacing) * 4.5);
}
{% endstylesheet %}
28 changes: 28 additions & 0 deletions liquid/components/aspect-ratio.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% doc %}
Fulldev UI aspect-ratio styles. Use native markup with its data-slot parts.
{% enddoc %}

{% stylesheet %}
/* Media at a fixed ratio, covered by its image on a muted fill until it loads. The caller rounds it
as its Fulldev UI block does; framed adds the rounded border of Fulldev UI's video. */
[data-slot='aspect-ratio'] {
position: relative;
overflow: hidden;
aspect-ratio: var(--ratio, 4 / 3);
background: var(--muted);
}
[data-slot='aspect-ratio'][data-variant='framed'] {
border: 1px solid var(--border);
border-radius: var(--radius-xl);
}
[data-slot='aspect-ratio'] > :is(img, svg, video, iframe, picture) {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
[data-slot='aspect-ratio'] > svg {
fill: color-mix(in oklch, var(--muted-foreground) 35%, transparent);
}
{% endstylesheet %}
Loading
Loading