Token导航 LogoToken导航

Agent Skill · 开发

gluestack-components(胶水叠层组件)

gluestack-components 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

gluestack-components 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 13,037。

总安装 1,035周安装 44GitHub Stars 142下载 363核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:gluestack-components(胶水叠层组件)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/gluestack-components
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill gluestack-components
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill gluestack-components

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

gluestack-components 用于处理 GitHub 仓库、Issue 和 Pull Request 协作信息。适合围绕代码变更和仓库状态进行整理与分析。可生成组件差异报告和协作事项摘要。

安装命令:npx skills add https://github.com/thebushidocollective/han --skill gluestack-components。建议确认权限范围和维护状态,注意是否会触发命令执行或文件读写。

来源仓库内路径:skills/gluestack-components

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/thebushidocollective/han --skill gluestack-com…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

gluestack-components 怎么安装?

在终端执行 npx skills add https://github.com/thebushidocollective/han --skill gluestack-components。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

gluestack-components 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

gluestack-components 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

gluestack-components 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

gluestack-components 用的人多吗?

公开数据是累计安装 1,035 次,近一周安装 44 次,下载 363 次,GitHub 142 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

gluestack-components 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
gluestack-components

胶水叠层组件 · 本页

1,035142需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

gluestack-ui - Components

Expert knowledge of gluestack-ui's universal component library for building accessible, performant UI across React and React Native platforms.

Overview

gluestack-ui provides 50+ unstyled, accessible components that work seamlessly on web and mobile. Components are copy-pasteable into your project and styled with NativeWind (Tailwind CSS for React Native).

Key Concepts

Component Installation

Add components using the CLI:

# Initialize gluestack-ui in your project
npx gluestack-ui init

# Add individual components
npx gluestack-ui add button
npx gluestack-ui add input
npx gluestack-ui add modal

# Add multiple components
npx gluestack-ui add button input select modal

# Add all components
npx gluestack-ui add --all

Component Anatomy

Every gluestack-ui component follows a consistent pattern:

import { Button, ButtonText, ButtonSpinner, ButtonIcon } from '@/components/ui/button';

// Components are composable with sub-components
<Button size="md" variant="solid" action="primary">
  <ButtonIcon as={PlusIcon} />
  <ButtonText>Add Item</ButtonText>
  <ButtonSpinner />
</Button>

Variants, Sizes, and Actions

Components support consistent prop APIs:

// Button variants
<Button variant="solid">Solid</Button>
<Button variant="outline">Outline</Button>
<Button variant="link">Link</Button>

// Button sizes
<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra Large</Button>

// Button actions (semantic colors)
<Button action="primary">Primary</Button>
<Button action="secondary">Secondary</Button>
<Button action="positive">Positive</Button>
<Button action="negative">Negative</Button>

Core Components

Button

Interactive button with loading states and icons:

import { Button, ButtonText, ButtonSpinner, ButtonIcon } from '@/components/ui/button';
import { SaveIcon } from 'lucide-react-native';

function SaveButton({ isLoading, onPress }: { isLoading: boolean; onPress: () => void }) {
  return (
    <Button
      size="md"
      variant="solid"
      action="primary"
      isDisabled={isLoading}
      onPress={onPress}
    >
      {isLoading ? (
        <ButtonSpinner />
      ) : (
        <ButtonIcon as={SaveIcon} />
      )}
      <ButtonText>{isLoading ? 'Saving...' : 'Save'}</ButtonText>
    </Button>
  );
}

Input

Text input with labels and validation:

import {
  FormControl,
  FormControlLabel,
  FormControlLabelText,
  FormControlHelper,
  FormControlHelperText,
  FormControlError,
  FormControlErrorIcon,
  FormControlErrorText,
} from '@/components/ui/form-control';
import { Input, InputField, InputSlot, InputIcon } from '@/components/ui/input';
import { AlertCircleIcon, MailIcon } from 'lucide-react-native';

function EmailInput({ value, onChange, error }: {
  value: string;
  onChange: (text: string) => void;
  error?: string;
}) {
  return (
    <FormControl isInvalid={!!error}>
      <FormControlLabel>
        <FormControlLabelText>Email</FormControlLabelText>
      </FormControlLabel>
      <Input variant="outline" size="md">
        <InputSlot pl="$3">
          <InputIcon as={MailIcon} />
        </InputSlot>
        <InputField
          placeholder="Enter your email"
          value={value}
          onChangeText={onChange}
          keyboardType="email-address"
          autoCapitalize="none"
        />
      </Input>
      {error ? (
        <FormControlError>
          <FormControlErrorIcon as={AlertCircleIcon} />
          <FormControlErrorText>{error}</FormControlErrorText>
        </FormControlError>
      ) : (
        <FormControlHelper>
          <FormControlHelperText>We'll never share your email</FormControlHelperText>
        </FormControlHelper>
      )}
    </FormControl>
  );
}

Select

Dropdown selection component:

import {
  Select,
  SelectTrigger,
  SelectInput,
  SelectIcon,
  SelectPortal,
  SelectBackdrop,
  SelectContent,
  SelectDragIndicatorWrapper,
  SelectDragIndicator,
  SelectItem,
} from '@/components/ui/select';
import { ChevronDownIcon } from 'lucide-react-native';

function CountrySelect({ value, onValueChange }: {
  value: string;
  onValueChange: (value: string) => void;
}) {
  return (
    <Select selectedValue={value} onValueChange={onValueChange}>
      <SelectTrigger variant="outline" size="md">
        <SelectInput placeholder="Select country" />
        <SelectIcon as={ChevronDownIcon} mr="$3" />
      </SelectTrigger>
      <SelectPortal>
        <SelectBackdrop />
        <SelectContent>
          <SelectDragIndicatorWrapper>
            <SelectDragIndicator />
          </SelectDragIndicatorWrapper>
          <SelectItem label="United States" value="us" />
          <SelectItem label="Canada" value="ca" />
          <SelectItem label="United Kingdom" value="uk" />
          <SelectItem label="Australia" value="au" />
        </SelectContent>
      </SelectPortal>
    </Select>
  );
}

Modal

Dialog overlay component:

import {
  Modal,
  ModalBackdrop,
  ModalContent,
  ModalHeader,
  ModalCloseButton,
  ModalBody,
  ModalFooter,
} from '@/components/ui/modal';
import { Heading } from '@/components/ui/heading';
import { Text } from '@/components/ui/text';
import { Button, ButtonText } from '@/components/ui/button';
import { CloseIcon, Icon } from '@/components/ui/icon';

function ConfirmModal({ isOpen, onClose, onConfirm, title, message }: {
  isOpen: boolean;
  onClose: () => void;
  onConfirm: () => void;
  title: string;
  message: string;
}) {
  return (
    <Modal isOpen={isOpen} onClose={onClose} size="md">
      <ModalBackdrop />
      <ModalContent>
        <ModalHeader>
          <Heading size="lg">{title}</Heading>
          <ModalCloseButton>
            <Icon as={CloseIcon} />
          </ModalCloseButton>
        </ModalHeader>
        <ModalBody>
          <Text>{message}</Text>
        </ModalBody>
        <ModalFooter>
          <Button variant="outline" action="secondary" onPress={onClose}>
            <ButtonText>Cancel</ButtonText>
          </Button>
          <Button action="negative" onPress={onConfirm}>
            <ButtonText>Delete</ButtonText>
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
}

Toast

Notification component:

import {
  Toast,
  ToastTitle,
  ToastDescription,
  useToast,
} from '@/components/ui/toast';

function NotificationExample() {
  const toast = useToast();

  const showToast = () => {
    toast.show({
      placement: 'top',
      render: ({ id }) => (
        <Toast nativeID={`toast-${id}`} action="success" variant="solid">
          <ToastTitle>Success!</ToastTitle>
          <ToastDescription>Your changes have been saved.</ToastDescription>
        </Toast>
      ),
    });
  };

  return (
    <Button onPress={showToast}>
      <ButtonText>Show Toast</ButtonText>
    </Button>
  );
}

Accordion

Expandable content sections:

import {
  Accordion,
  AccordionItem,
  AccordionHeader,
  AccordionTrigger,
  AccordionTitleText,
  AccordionIcon,
  AccordionContent,
  AccordionContentText,
} from '@/components/ui/accordion';
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react-native';

function FAQAccordion({ items }: { items: { question: string; answer: string }[] }) {
  return (
    <Accordion type="multiple" defaultValue={['item-0']}>
      {items.map((item, index) => (
        <AccordionItem key={index} value={`item-${index}`}>
          <AccordionHeader>
            <AccordionTrigger>
              {({ isExpanded }) => (
                <>
                  <AccordionTitleText>{item.question}</AccordionTitleText>
                  <AccordionIcon as={isExpanded ? ChevronUpIcon : ChevronDownIcon} />
                </>
              )}
            </AccordionTrigger>
          </AccordionHeader>
          <AccordionContent>
            <AccordionContentText>{item.answer}</AccordionContentText>
          </AccordionContent>
        </AccordionItem>
      ))}
    </Accordion>
  );
}

Checkbox and Radio

Selection controls:

import {
  Checkbox,
  CheckboxIndicator,
  CheckboxIcon,
  CheckboxLabel,
} from '@/components/ui/checkbox';
import {
  RadioGroup,
  Radio,
  RadioIndicator,
  RadioIcon,
  RadioLabel,
} from '@/components/ui/radio';
import { CheckIcon, CircleIcon } from 'lucide-react-native';

function TermsCheckbox({ isChecked, onChange }: {
  isChecked: boolean;
  onChange: (checked: boolean) => void;
}) {
  return (
    <Checkbox value="terms" isChecked={isChecked} onChange={onChange}>
      <CheckboxIndicator>
        <CheckboxIcon as={CheckIcon} />
      </CheckboxIndicator>
      <CheckboxLabel>I agree to the terms and conditions</CheckboxLabel>
    </Checkbox>
  );
}

function ShippingOptions({ value, onChange }: {
  value: string;
  onChange: (value: string) => void;
}) {
  return (
    <RadioGroup value={value} onChange={onChange}>
      <Radio value="standard">
        <RadioIndicator>
          <RadioIcon as={CircleIcon} />
        </RadioIndicator>
        <RadioLabel>Standard Shipping (5-7 days)</RadioLabel>
      </Radio>
      <Radio value="express">
        <RadioIndicator>
          <RadioIcon as={CircleIcon} />
        </RadioIndicator>
        <RadioLabel>Express Shipping (2-3 days)</RadioLabel>
      </Radio>
      <Radio value="overnight">
        <RadioIndicator>
          <RadioIcon as={CircleIcon} />
        </RadioIndicator>
        <RadioLabel>Overnight Shipping (1 day)</RadioLabel>
      </Radio>
    </RadioGroup>
  );
}

Best Practices

1. Use Composition Over Configuration

Compose components with sub-components for flexibility:

// Good: Composable structure
<Button>
  <ButtonIcon as={PlusIcon} />
  <ButtonText>Add</ButtonText>
</Button>

// Avoid: Prop-heavy configuration
<Button icon={PlusIcon} text="Add" iconPosition="left" />

2. Leverage FormControl for Form Fields

Wrap inputs in FormControl for consistent validation:

<FormControl isRequired isInvalid={!!error}>
  <FormControlLabel>
    <FormControlLabelText>Password</FormControlLabelText>
  </FormControlLabel>
  <Input>
    <InputField type="password" />
  </Input>
  <FormControlError>
    <FormControlErrorText>{error}</FormControlErrorText>
  </FormControlError>
</FormControl>

3. Handle Platform Differences

Use platform-specific logic when needed:

import { Platform } from 'react-native';

function ResponsiveModal({ children }: { children: React.ReactNode }) {
  return (
    <Modal size={Platform.OS === 'web' ? 'lg' : 'full'}>
      <ModalContent>
        {children}
      </ModalContent>
    </Modal>
  );
}

4. Use Proper Loading States

Show loading feedback for async operations:

function SubmitButton({ isLoading, onPress }: {
  isLoading: boolean;
  onPress: () => void;
}) {
  return (
    <Button isDisabled={isLoading} onPress={onPress}>
      {isLoading && <ButtonSpinner mr="$2" />}
      <ButtonText>{isLoading ? 'Submitting...' : 'Submit'}</ButtonText>
    </Button>
  );
}

5. Create Reusable Component Wrappers

Build app-specific components on top of gluestack-ui:

// components/app/PrimaryButton.tsx
import { Button, ButtonText, ButtonSpinner } from '@/components/ui/button';

interface PrimaryButtonProps {
  children: string;
  isLoading?: boolean;
  onPress: () => void;
}

export function PrimaryButton({ children, isLoading, onPress }: PrimaryButtonProps) {
  return (
    <Button
      size="lg"
      variant="solid"
      action="primary"
      isDisabled={isLoading}
      onPress={onPress}
      className="rounded-full"
    >
      {isLoading && <ButtonSpinner mr="$2" />}
      <ButtonText>{children}</ButtonText>
    </Button>
  );
}

Common Patterns

Form with Validation

import { useState } from 'react';
import { VStack } from '@/components/ui/vstack';
import { Button, ButtonText } from '@/components/ui/button';
import { FormControl, FormControlError, FormControlErrorText } from '@/components/ui/form-control';
import { Input, InputField } from '@/components/ui/input';

interface FormData {
  email: string;
  password: string;
}

interface FormErrors {
  email?: string;
  password?: string;
}

function LoginForm({ onSubmit }: { onSubmit: (data: FormData) => void }) {
  const [formData, setFormData] = useState<FormData>({ email: '', password: '' });
  const [errors, setErrors] = useState<FormErrors>({});

  const validate = (): boolean => {
    const newErrors: FormErrors = {};

    if (!formData.email) {
      newErrors.email = 'Email is required';
    } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
      newErrors.email = 'Invalid email format';
    }

    if (!formData.password) {
      newErrors.password = 'Password is required';
    } else if (formData.password.length < 8) {
      newErrors.password = 'Password must be at least 8 characters';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = () => {
    if (validate()) {
      onSubmit(formData);
    }
  };

  return (
    <VStack space="md">
      <FormControl isInvalid={!!errors.email}>
        <Input>
          <InputField
            placeholder="Email"
            value={formData.email}
            onChangeText={(text) => setFormData({ ...formData, email: text })}
          />
        </Input>
        <FormControlError>
          <FormControlErrorText>{errors.email}</FormControlErrorText>
        </FormControlError>
      </FormControl>

      <FormControl isInvalid={!!errors.password}>
        <Input>
          <InputField
            placeholder="Password"
            type="password"
            value={formData.password}
            onChangeText={(text) => setFormData({ ...formData, password: text })}
          />
        </Input>
        <FormControlError>
          <FormControlErrorText>{errors.password}</FormControlErrorText>
        </FormControlError>
      </FormControl>

      <Button onPress={handleSubmit}>
        <ButtonText>Login</ButtonText>
      </Button>
    </VStack>
  );
}

Data List with Actions

import { HStack } from '@/components/ui/hstack';
import { VStack } from '@/components/ui/vstack';
import { Box } from '@/components/ui/box';
import { Text } from '@/components/ui/text';
import { Heading } from '@/components/ui/heading';
import { Button, ButtonIcon } from '@/components/ui/button';
import { Pressable } from '@/components/ui/pressable';
import { TrashIcon, EditIcon } from 'lucide-react-native';

interface Item {
  id: string;
  title: string;
  description: string;
}

function ItemList({ items, onEdit, onDelete }: {
  items: Item[];
  onEdit: (id: string) => void;
  onDelete: (id: string) => void;
}) {
  return (
    <VStack space="sm">
      {items.map((item) => (
        <Box
          key={item.id}
          className="p-4 bg-background-50 rounded-lg border border-outline-200"
        >
          <HStack justifyContent="space-between" alignItems="center">
            <VStack space="xs" flex={1}>
              <Heading size="sm">{item.title}</Heading>
              <Text size="sm" className="text-typography-500">
                {item.description}
              </Text>
            </VStack>
            <HStack space="xs">
              <Button
                size="sm"
                variant="outline"
                action="secondary"
                onPress={() => onEdit(item.id)}
              >
                <ButtonIcon as={EditIcon} />
              </Button>
              <Button
                size="sm"
                variant="outline"
                action="negative"
                onPress={() => onDelete(item.id)}
              >
                <ButtonIcon as={TrashIcon} />
              </Button>
            </HStack>
          </HStack>
        </Box>
      ))}
    </VStack>
  );
}

Anti-Patterns

Do Not Mix Styling Approaches

// Bad: Mixing inline styles with NativeWind
<Button style={{ backgroundColor: 'blue' }} className="p-4">
  <ButtonText>Click</ButtonText>
</Button>

// Good: Use NativeWind classes consistently
<Button className="bg-blue-500 p-4">
  <ButtonText>Click</ButtonText>
</Button>

Do Not Skip Accessibility Props

// Bad: Missing accessibility information
<Pressable onPress={handlePress}>
  <Icon as={MenuIcon} />
</Pressable>

// Good: Include accessibility props
<Pressable
  onPress={handlePress}
  accessibilityLabel="Open menu"
  accessibilityRole="button"
>
  <Icon as={MenuIcon} />
</Pressable>

Do Not Ignore Platform Constraints

// Bad: Using web-only APIs on native
<Modal>
  <ModalContent onClick={handleClick}> {/* onClick doesn't work on native */}
    ...
  </ModalContent>
</Modal>

// Good: Use cross-platform events
<Modal>
  <ModalContent>
    <Pressable onPress={handlePress}>
      ...
    </Pressable>
  </ModalContent>
</Modal>

Do Not Hardcode Colors

// Bad: Hardcoded colors
<Box className="bg-[#3B82F6]">
  <Text className="text-[#FFFFFF]">Hello</Text>
</Box>

// Good: Use theme tokens
<Box className="bg-primary-500">
  <Text className="text-typography-0">Hello</Text>
</Box>

Related Skills

  • gluestack-theming: Customizing themes and design tokens
  • gluestack-accessibility: Ensuring accessible implementations

平台分布

Codex

36.97%
按下载量换算134

Claude

25.37%
按下载量换算92

Cursor

19.45%
按下载量换算71

Gemini CLI

9.43%
按下载量换算34

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills